Axios.js-拦截器原理分析

拦截器函数-请求/响应的回调函数调用顺序,代码测试:

    // 设置请求拦截器  config 配置对象
        axios.interceptors.request.use(function one(config) {
            console.log('请求拦截器 成功 - 1号');
            return config;
        }, function one(error) {
            console.log('请求拦截器 失败 - 1号');
            return Promise.reject(error);
        });

        axios.interceptors.request.use(function two(config) {
            console.log('请求拦截器 成功 - 2号');
            return config;
        }, function two(error) {
            console.log('请求拦截器 失败 - 2号');
            return Promise.reject(error);
        });

        // 设置响应拦截器
        axios.interceptors.response.use(function (response) {
            console.log('响应拦截器 成功 1号');
            return response;
        }, function (error) {
            console.log('响应拦截器 失败 1号')
            return Promise.reject(error);
        });

        axios.interceptors.response.use(function (response) {
            console.log('响应拦截器 成功 2号')
            return response;
        }, function (error) {
            console.log('响应拦截器 失败 2号')
            return Promise.reject(error);
        });

        //发送请求
        axios({
            method: 'GET',
            url: 'http://localhost:3000/posts'
        }).then(response => {
            console.log(response);
        });

控制台打印的结果:

 这里请求拦截器为什么是先2号后1号,而响应拦截器则按顺序输出?(当时我觉得跟堆栈有关),秉着大胆假设,小心求证的探索思想,决定从源码着手分析,究竟藏了啥玄机。

注意: 此流程是通过 promise 串连起来的请求拦截器传递的是 config, 响应
拦截器传递的是 response。

axios github获取源码  |    axios 官方文档  |  axios 中文文档

下载后,找到路径下node_modules -》lib -》core -》Axios.js

注意不是dist文件夹下,这个是webpack工具打包输出路径 。

axios.interceptors.request.use 说明

首先,搞清楚axios对象里的interceptors属性哪来的?

/**
 * Create a new instance of Axios
 * 创建 Axios 构造函数
 * @param {Object} instanceConfig The default config for the instance
 */
function Axios(instanceConfig) {
    //实例对象上的 defaults 属性为配置对象
    this.defaults = instanceConfig;
    //实例对象上有 interceptors 属性用来设置请求和响应拦截器
    this.interceptors = {
        request: new InterceptorManager(),
        response: new InterceptorManager()
    };
}

 Axios 构造函数,通过this关键字指定的属性,另外还有默认配置对象defaults。

 第二,request哪来的?

this.interceptors 是个对象,包含两个属性request和response。

第三,use方法哪来的?

request属性对应的值是一个 InterceptorManager实例对象,use是其中的方法。

 进入InterceptorManager.js ,调用use方法:

InterceptorManager.prototype.use = function use(fulfilled, rejected) {
  this.handlers.push({
    fulfilled: fulfilled,
    rejected: rejected
  });
  return this.handlers.length - 1;
};

第四,this.handlers哪来的?

function InterceptorManager() {
  //创建一个属性
  this.handlers = [];
}

InterceptorManager构造函数,new后添加的属性,是个空数组。

 第五,push操作

往this.handles空数组增添一个对象,(两个属性ulfilled和rejected),这就呼应了前边axios调用use方法后所执行的成功和失败回调。

 进入Axios.js的request方法中:

Axios.prototype.request = function request(config) {
   // ......
// Hook up interceptors middleware
    // 创建拦截器中间件  第一个参数用来发送请求, 第二个为 undefined 用来补位
    var chain = [dispatchRequest, undefined];
    // 创建一个成功的 promise 且成功的值为合并后的请求配置
    var promise = Promise.resolve(config);//  promise 成功的Promise
    // 遍历实例对象的请求拦截器,
    this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
        //将请求拦截器压入数组的最前面
        chain.unshift(interceptor.fulfilled, interceptor.rejected);
    });

    this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
        //将相应拦截器压入数组的最尾部
        chain.push(interceptor.fulfilled, interceptor.rejected);
    });

    //如果链条长度不为 0
    while (chain.length) {
        //依次取出 chain 的回调函数, 并执行
        promise = promise.then(chain.shift(), chain.shift());
    }

    return promise;
};

第六,拦截器实例forEach哪来的?

InterceptorManager.prototype.forEach = function forEach(fn) {
  utils.forEach(this.handlers, function forEachHandler(h) {
    if (h !== null) {
      fn(h);
    }
  });
};

InterceptorManager原型上添加的方法,实际是遍历request对象中handles数组。

第七,chain拦截器中间件分析 。

依自己理解画的示意图(有点丑):

 chain初始值有2个元素,分别是[dispatchRequest, undefined]。开始遍历的是request拦截器对象handles数组,追加方式是unshift,将请求拦截器压入数组最前面,而每个对象按照成功回调在前,失败回调在后,此时共有6个元素了;然后遍历response拦截器对象,对象内部放置顺序与上面相同,所以最终一共存了10个元素。

 第八,取出chain的回调函数。

依据chain.length判定,成功的回调函数会先执行,所以依次从头往后调用two(config)-》two(error),然后返回一个promise对象;此时数组长度为8,条件为真,接着调用one(config)-》one(error),。。。直至条件不满足。

 执行顺序如上,这里指的都是成功的回调,最后客户端拿到promise对象,通过then语法获取请求的数据结果。

在这个过程中,use方法并没有做特别的事情,它只是将两个回调函数保存在request(response)中属性handles这个数组里。

总结一波:在开始调axios(request)时,handles数组把请求拦截器对象往前边放,把响应拦截器往后边放,以跳板的形式(chain初始值)循环遍历取出回调。顺带提一下,如果请求拦截器返回一个失败回调,那么它最终以undefined呈现,发生异常穿透,这是promise的一个特性。

参考:Axios源码分析 | 技术分享 |  Web前端axios入门与源码解析

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值