前言
在上一篇文章中,我们对axios核心文件Axios.js的内容做了学习分析。
其内容主要包含5个部分:小模块的导入、Axios函数对象的声明、原型方法request和getUri、给请求方法设置别名和导出Axios对象。其中最为重要的内容就是原型方法request的部分,里面对于拦截器的处理更是重中之重,所以我们继续对拦截器和相关内容进行更深入的探究。
拦截器导引
实际在上文中,我们就提到了拦截器的几个内容
- interceptors.request.use
- interceptors.request.forEach
use方法和forEach方法都是拦截器对象内部实现的方法。看到forEach,是不是很多人认为拦截器对象内部有一个数组?是也不是,具体如何,在下面内容中细说。
拦截器分析
内容梗概
拦截器的实现是在与Axios.js文件同级目录下的InterceptorManager.js中,内容也可以分为几部分:
- 拦截器声明
- 拦截器挂载use方法
- 拦截器挂载eject方法
- 拦截器挂载forEach方法
- 拦截器对象导出
拦截器声明
代码实现
function InterceptorManager() {
this.handlers = [];
}
内容分析
在拦截器的构造函数中,使用了handlers来存储拦截器。可以看到hanlders是数组类型数据,但是在这里更精准的称呼是栈。没错,就是数据结构中的栈,拥有先进后出的特点。
具体的使用,留后详述。
拦截器挂载use方法
代码实现
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;
};
内容分析
use方法的作用是将一个新的拦截器对象添加到栈中,接收是三个参数: 完成状态方法、失败状态方法、配置项。
- fulfilled和rejected为函数,也就是我们在使用时注册拦截器传入的两个函数
- synchronous表示根据参数中的配置项来决定是否采用异步处理
- runWhen是可以使用options暴露出去的配置,用来标记一些在运行时需要检测的拦截器
需要注意的还有一点,use方法最后返回的值为栈的元素数量-1,即为最后被压入栈中的拦截器所处位置,后面在eject方法有用到
拦截器挂载eject方法
代码实现
InterceptorManager.prototype.eject = function eject(id) {
if (this.handlers[id]) {
this.handlers[id] = null;
}
};
内容分析
eject方法的作用就是从栈中移除一个拦截器对象。栈有先进后出的特点,本来以为是从栈中出栈,但代码的实现却是将移除位置的内容置为null。
不是很理解这些做法,有大神知道可以评论下吗?
参数中传入的id就是use方法的返回值,即为拦截器在栈中的位置
根据id去获取拦截器对象,如果存在改拦截器对象,就将栈中该位置的值置为null
拦截器挂载forEach方法
代码实现
InterceptorManager.prototype.forEach = function forEach(fn) {
utils.forEach(this.handlers, function forEachHandler(h) {
if (h !== null) {
fn(h);
}
});
};
内容分析
代码的实现也说明了拦截器中的forEach其实不是真正的数组的方法,是经过一层封装的。
在执行forEach的时候需要跳过栈中值为null的位置,在这些位置,不需要执行调用,就避免了执行出错的情况
拦截器对象导出
module.exports = InterceptorManager;
|