Axios 中的公共方法
1、关键点
假设1个请求拦截和1个相应拦截
一开始栈的数据就两个(dispatchRequest是 ajax请求)
[dispatchRequest ,undefined] --> undefined 是为了后面一对一对的
如果拦截器存在,就要往栈中加数据 (unshift)
[rejected1, fulfilled1, dispatchRequest, undefined]
请求结束后,如果还有拦截,就要继续添加,(添加在请求完后面 push)
[rejected1, fulfilled1, dispatchRequest, undefined, fulfilled1, rejected1]
每次出栈就一对的出栈,因为 promise 一个成功一个失败,
2、使用
// 拦截器
const myInterceptor = axios.interceptors.request.use(function (config) {
// 在发送之前做点什么
console.log(request1)
return config
}, function(error) {
// 在请求错误做些什么
return error
})
axios.interceptors.request.use(function (config) {
// 在发送之前做点什么
console.log(request2)
return config
}, function(error) {
// 在请求错误做些什么
return error
})
axios.interceptors.response.use(function (config) {
// 在发送之前做点什么
console.log(request1)
return config
}, function(error) {
// 在请求错误做些什么
return error
})
axios.interceptors.response.use(function (config) {
// 在发送之前做点什么
console.log(request2)
return config
}, function(error) {
// 在请求错误做些什么
return error
})
// 移除拦截器
axios.interceptors.request.eject(myInterceptor)
// 执行顺序 request2 -> request1 -> response1 -> response2
3、源码(综合了前面的源码)
import InterceptorManager from './InterceptorManager.js'
import dispatchRequest from './dispatchRequest.js'
// 1、配置:外部传入,可覆盖内部默认配置
// 2、拦截器:实例后,开发者可通过 `use` 方法注册成功和失败的钩子函数,
// 比如 `axios.interceptors.request.use((config)=>config,(error)=>error);`
function Axios(instanceConfig) {
// 配置
this.defaults = instanceConfig;
// 拦截器实例
// 每个 Axios 实例上都有 interceptors 属性,该属性上有 request、response 属性,
// 分别都是一个 InterceptorManager 实例,而 InterceptorManager 构造函数就是
// 用来管理拦截器
this.interceptors = {
request: new InterceptorManager(),
response: new InterceptorManager()
};
}
生成请求与响应拦截队列,形成promise链(综合了上一篇的)
Axios.prototype.request = function request(config) {
// 为了支持 request(url, {...}), request({url, ...})
// 方式二:axios('https://xxxx') ,判断参数字符串,则赋值给 config.url
if (typeof config === 'string') {
config = arguments[1] || {};
config.url = arguments[0];
} else {
// 方式一:axios({}) ,参数为对象,则直接赋值给 config
config = config || {};
}
// 配置优先级: 调用方法的配置 > 实例化axios的配置 > 默认配置
// 举个例子,类似:axios.get(url, {}) > axios.create(url, {}) > 内部默认设置
config = mergeConfig(this.defaults, config);
// 生成请求拦截队列
var requestInterceptorChain = [];
this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected);
});
// 生成响应拦截队列
var responseInterceptorChain = [];
this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected);
});
/*
创建用于保存请求/响应拦截函数的数组
数组的中间放发送请求的函数
数组的左边放请求拦截器函数(成功/失败)
数组的右边放响应拦截器函数
undefined为啥? --> 因为拦截器是成对存在的,所以此处用undefined占位,后续在promise链中可以同前面的一对一对拿出移除
*/
// 编排整个请求的任务队列
// 派发请求 dispatchRequest 看下篇
var chain = [dispatchRequest, undefined];
// 为什么unshift要用Array.prototype.unshift.apply??
Array.prototype.unshift.apply(chain, requestInterceptorChain);
chain.concat(responseInterceptorChain);
var promise;
// 传入配置
promise = Promise.resolve(config);
// 形成 promise 链条调用
// 循环 chain ,不断从 chain 中取出设置的任务,通过 Promise 调用链执行 , 一对一对拿出,一个成功一个失败处理
while (chain.length) {
promise = promise.then(chain.shift(), chain.shift());
}
// ...
return promise;
};
// Provide aliases for supported request methods utils.forEach(数组, 函数)-> 循环数组并执行函数
utils.forEach(['delete', 'get', 'head', 'options'], function forEachMethodNoData(method) {
/*eslint func-names:0*/
Axios.prototype[method] = function(url, config) {
return this.request(utils.merge(config || {}, {
method: method,
url: url
}));
};
});
// 与平时用的forEach的区别:对象也可以传,并遍历出对象的键值
utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
/*eslint func-names:0*/
Axios.prototype[method] = function(url, data, config) {
return this.request(utils.merge(config || {}, {
method: method,
url: url,
data: data
}));
};
});
定义拦截器:
handlers []: 存放 use 注册的回调函数
use function: 注册成功和失败的回调函数
eject function: 删除注册过的函数
// 拦截器
export class InterceptorManager {
constructor() {
// 存放所有拦截器的栈
this.handlers = []
}
use (fulfilled, rejected) {
this.handlers.push({
fulfilled,
rejected
})
// 返回id,便于取消
return this.handlers.length - 1
}
// 取消一个拦截器
eject (id) {
if (this.handlers[id]) {
this.handlers[id] = null
}
}
// 执行栈中所有的handler
forEach(fn) {
this.handlers.forEach(item => {
// 此处过滤掉已取消的
if (item) {
fn(item)
}
})
}
}