接口分析
https://github.com/axios/axio…
一般用法
// Add a request interceptor
axios.interceptors.request.use(function (config) {
// Do something before request is sent
return config;
}, function (error) {
// Do something with request error
return Promise.reject(error);
});
// Add a response interceptor
axios.interceptors.response.use(function (response) {
// Any status code that lie within the range of 2xx cause this function to trigger
// Do something with response data
return response;
}, function (error) {
// Any status codes that falls outside the range of 2xx cause this function to trigger
// Do something with response error
return Promise.reject(error);
});
删除拦截器
const myInterceptor = axios.interceptors.request.use(function () {/*...*/});
axios.interceptors.request.eject(myInterceptor);
同步解决
axios.interceptors.request.use(function (config) {
config.headers.test = 'I am only a header!';
return config;
}, null, {synchronous: true});
条件执行
function onGetCall(config) {return config.method === 'get';}
axios.interceptors.request.use(function (config) {
config.headers.test = 'special get headers';
return config;
}, null, {runWhen: onGetCall});
提出问题:
a. interceptor 是如何实现申请的前置解决和后置解决?
b. 为什么 request interceptor 要思考同步执行?
https://github.com/axios/axio… 里提到,默认 synchronous 为 false,是异步执行的。当 js 主线程梗塞的时候,就会导致提早执行 request interceptor。这里波及到了 event loop 模型的常识,js 引擎会先执行同步代码,执行完了,会去查看工作队列,看看有没有异步工作的后果,有的话推送到执行栈执行。那咱们上面看看它是如何实现同步执行的。
源码剖析
- 提取关键字
interceptors
,定位到Axios.js
、InterceptorManager.js
-
查看 InterceptorManager.js
var utils = require("./../utils"); function InterceptorManager() {this.handlers = []; } InterceptorManager.prototype.use = function use(fulfilled, rejected, options) { this.handlers.push({ fulfilled: fulfilled, rejected: rejected, // 是否同步执行 synchronous: options ? options.synchronous: false, // 执行条件 runWhen: options ? options.runWhen: null }); return this.handlers.length - 1; }; // 重置 interceptor 为 null,留神不是删除 InterceptorManager.prototype.eject = function eject(id) {if (this.handlers[id]) {this.handlers[id] = null; } }; // 专属的递归器,次要逻辑就是如果不是 null 就执行执行器 InterceptorManager.prototype.forEach = function forEach(fn) { utils.forEach(this.handlers, function forEachHandler(h) {if (h !== null) {fn(h); } }); }; module.exports = InterceptorManager;
顺便贴一下 util.js 的 forEach 办法,实质上就是对 obj 进行 for 循环,对每个元素执行回调
function forEach(obj, fn) { // Don't bother if no value provided if (obj === null || typeof obj === 'undefined') {return;} // Force an array if not already something iterable if (typeof obj !== 'object') { /*eslint no-param-reassign:0*/ obj = [obj]; } if (isArray(obj)) { // Iterate over array values for (var i = 0, l = obj.length; i < l; i++) {fn.call(null, obj[i], i, obj); } } else { // Iterate over object keys for (var key in obj) {if (Object.prototype.hasOwnProperty.call(obj, key)) {fn.call(null, obj[key], key, obj); } } } }
小结一下,InterceptorManager 类,设计了收集、移除、递归 interceptor 的性能
-
再看 Axios.js
line18~21:初始化 interceporthis.interceptors = {request: new InterceptorManager(), response: new InterceptorManager()};
line60~118: 过滤 interceptors,并合并解决
var requestInterceptorChain = []; var synchronousRequestInterceptors = true; // 用 InterceptorManager 的 forEach 办法,曾经过滤为 null 的 interceptor this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {if (typeof interceptor.runWhen === 'function' && interceptor.runWhen(config) === false) {return;} // 对于同步执行的 request 相干的 interceptor 逻辑,前面咱们再回头来看。这里的逻辑就是要么全副是同步执行,要么全副是异步执行。只有有一个是异步,则全副用异步的办法执行。synchronousRequestInterceptors = synchronousRequestInterceptors && interceptor.synchronous; requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected); }); var responseInterceptorChain = []; this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected); }); var promise; // request 的 interceptor 以异步模式执行 if (!synchronousRequestInterceptors) {// 这里要结构 [onFullfilled, onRejected] 格局,以便下边应用 promise.then 办法来执行。var chain = [dispatchRequest, undefined]; // 合并操作:先执行 request 的 interceptor,再发动申请,最初再执行 response 的 interceptor Array.prototype.unshift.apply(chain, requestInterceptorChain); chain.concat(responseInterceptorChain); // 新建 proise,并执行。所以 interceptor 的原理是在发动申请前做一些列操作,而后发动申请,最初执行返回后的操作。很天然会想到 promise 操作 promise = Promise.resolve(config); while (chain.length) {promise = promise.then(chain.shift(), chain.shift()); } return promise; } // request 的 interceptor 以同步模式执行 var newConfig = config; while (requestInterceptorChain.length) {var onFulfilled = requestInterceptorChain.shift(); var onRejected = requestInterceptorChain.shift(); try { // 同步执行 onFulfilled 办法 newConfig = onFulfilled(newConfig); } catch(error) { // 同步执行 onRejected 办法 onRejected(error); break; } } // 异步发动申请 try {promise = dispatchRequest(newConfig); } catch(error) {return Promise.reject(error); } // 异步执行 response 的 interceptor while (responseInterceptorChain.length) {promise = promise.then(responseInterceptorChain.shift(), responseInterceptorChain.shift()); } return promise; };
小结一下,Axios.js 这段操作,次要做了一下这些工作:
- 过滤 request 的 interceptor:通过 forEach 办法、runWhen 参数
- 决定 request 的 interceptor 是同步执行还是异步执行:因为批处理,要么都是同步执行,要么都是异步执行
- 把符合要求 request interceptor 推入 requestInterceptorChain
- 过滤 response 的 interceptor:通过 forEach 办法
- 把符合要求 response interceptor 推入 responseInterceptorChain
- 如果 request 的 interceptor 是异步执行,那么合并操作:request interceptor、发动申请、response interceptor,用 promise.then 操作来生产这些操作
- 如果 request 的 interceptor 是同步执行,那么同步执行 request 的 interceptor,而后用 promise.then 异步发动申请、异步解决 response interceptor
- 返回 promise
值得借鉴的中央
- InterceptorManager 的实现中,eject 办法,是间接置 null,而不是删除元素。如果须要无效的元素,则再写一个过滤办法来获取。这样的益处的不会扭转前面元素的 index。
- 结构 [onFullfilled, onRejected] 数据格式,巧用 promise.then 来生产一系列操作。
总结
- interceptor 自身就是一个收集解决的对象
- axios 是通过合并前置操作、发动申请、后置操作,而后用 promise.then 来生产一些列操作。