1. 拦截器应用办法
// 申请拦截器1 axios.interceptors.request.use(options => { console.log('1') return options }) // 申请拦截器2 axios.interceptors.request.use(options => { console.log('2') return options })
相应拦截器
// 相应拦截器1axios.interceptors.response.use(options => { console.log('2') return options})// 响应拦截器2axios.interceptors.response.use(options => { console.log('1') return options})
发送申请
axios(options).then(function (res) {}).catch(function (res) {});
执行成果
留神点:申请拦截器先退出的后执行,响应拦截器先退出的先执行
2. 拦截器对应源码实现
axios.interceptors.response.use调用的对应函数\lib\core\InterceptorManager.js
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;};
接管拦截器执行胜利回调,失败回调和配置参数,上方示例只增加了拦截器执行胜利回调,相当于rejected是undefined, return this.handlers.length - 1 返回以后拦截器的id,不便后续勾销拦截器
顺便看下拦截器的勾销
InterceptorManager.prototype.eject = function eject(id) { if (this.handlers[id]) { this.handlers[id] = null; }};
将对应id的拦截器置为空,想勾销拦截器即可调用axios.interceptors.request.eject(1),这里勾销了索引为1,即第二个申请拦截器
拦截器与真正申请的组合调用形式
axios(options).then(function (res) {}).catch(function (res) {});发送申请时,执行了Axios.prototype.request
Axios.prototype.request = function request(config) { // filter out skipped interceptors var requestInterceptorChain = []; var synchronousRequestInterceptors = true; this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) { // options ? options.synchronous : false, synchronousRequestInterceptors = synchronousRequestInterceptors && interceptor.synchronous; // 向数组结尾增加(多个参数示意多个元素) // 为什么间接拜访了interceptor.fulfilled而不是interceptor.handlers.fulfilled, requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected); }); var responseInterceptorChain = []; this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) { responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected); }); var promise; if (!synchronousRequestInterceptors) { var chain = [dispatchRequest, undefined]; // unshift() 办法可向数组的结尾增加一个或更多元素,并返回新的长度。 Array.prototype.unshift.apply(chain, requestInterceptorChain); chain.concat(responseInterceptorChain); /* 将现有对象转为 Promise 对象 Promise.resolve('foo') // 等价于 new Promise(resolve => resolve('foo')) */ promise = Promise.resolve(config); while (chain.length) { // 调用拦截器,申请连 promise = promise.then(chain.shift(), chain.shift()); } return promise; } var newConfig = config; while (requestInterceptorChain.length) { // 删除第一个元素并返回第一个元素 var onFulfilled = requestInterceptorChain.shift(); var onRejected = requestInterceptorChain.shift(); try { newConfig = onFulfilled(newConfig); } catch (error) { onRejected(error); break; } } try { promise = dispatchRequest(newConfig); } catch (error) { return Promise.reject(error); } while (responseInterceptorChain.length) { promise = promise.then(responseInterceptorChain.shift(), responseInterceptorChain.shift()); } return promise;};
上方源码只粘贴了次要代码
别离遍历申请拦截器个响应拦截器,像申请拦截器数组后方和响应拦截器前方顺次增加拦截器胜利回调和失败回调,定义一个真正发动申请时执行的函数数组var chain = [dispatchRequest, undefined];别离在后方退出申请拦截器,前方退出返回拦截器,最初chain形如
[申请拦截器胜利回调函数, 申请拦截器失败回调函数,dispatchRequest,undefined,响应拦截器胜利回调函数,响应拦截器失败回调函数]
遍历chain 顺次用promise链去执行:如:
while (chain.length) { // 调用拦截器,申请连 promise = promise.then(chain.shift(), chain.shift()); }
测试执行过程
let fun1 = function (e) { console.log('拦截器1胜利函数', '上一个函数返回的参数', e) return 1 } let fun2 = function (e) { console.log('真正发动申请', '上一个函数返回的参数', e) return 2 } let fun3 = function (e) { console.log('响应拦截器1胜利函数', '上一个函数返回的参数', e) return 3 } let arr = [fun1, undefined, fun2, undefined, fun3, undefined] let promise = Promise.resolve(9); while (arr.length) { promise = promise.then(arr.shift(), arr.shift()); } promise.then(res => { console.log('最初拿到的数据', res) })
执行后果
更多对于axios的具体解析:若川大佬的源码解析系列