【axios源码阅读】 1 拦截器如何工作


axios中拦截器分为请求拦截器和相应拦截器,请求拦截器用于在request之前的预处理,比如带上token,相应拦截器可以对response做统一处理。

初始化

首先看一下Interceptor的初始化过程, 在axios实例上由变量interceptors统一保管拦截器,拦截器内部就是一个普通array。

//Axios.js
function Axios(instanceConfig) {
  this.defaults = instanceConfig;
  //拦截器
  this.interceptors = {
    request: new InterceptorManager(),
    response: new InterceptorManager()
  };
}

//InterceptorManager.js
function InterceptorManager() {
  this.handlers = [];
}

添加拦截器

在axios中使用use函数添加Interceptor,下面看一下use函数的code

//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;
};

use方法调用时将一个对象添加到handlers中,fulfilled是请求/相应成功时调用的函数,rejected就是失败回调。

synchronous代表该拦截器是同步还是异步调用,默认情况下拦截器都是异步的,且只有所有拦截器都是同步的才会进入同步调用。

拦截器的执行过程

拦截器会在request(axios的核心请求函数)请求时执行。

//Axios.js/request
var requestInterceptorChain = [];
var synchronousRequestInterceptors = true;
this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
  if (typeof interceptor.runWhen === 'function' && interceptor.runWhen(config) === false) {
    return;
  }
  //只要有一个拦截器是异步的,那么所有拦截器都异步调用
  //如果所有拦截器都是同步的才进行同步调用
  synchronousRequestInterceptors = synchronousRequestInterceptors && interceptor.synchronous;
  requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected);
});

var responseInterceptorChain = [];
this.interceptors.response.forEach(functionpushResponseInterceptors(interceptor) {
  responseInterceptorChain.push(interceptor.fulfilled,interceptor.rejected);
});

首先取出handlers中的拦截器,然后放入array中用于后续执行。

下面是拦截器异步执行的过程,这里使用unshift和concat将请求拦截器,request,响应拦截器拼接,按照顺序依次执行就可以实现先执行requestInterceptor,然后调用request,最后执行responseInterceptor。

然后先生成一个fulfilled状态的promise用于支持链式调用,通过while将promise.then连接在一起就实现了interceptor的异步链式调用。

if (!synchronousRequestInterceptors) {
  //拼接拦截器数组
  var chain = [dispatchRequest, undefined];
  Array.prototype.unshift.apply(chain, requestInterceptorChain);
  chain = chain.concat(responseInterceptorChain);
  promise = Promise.resolve(config);
  while (chain.length) {
    promise = promise.then(chain.shift(), chain.shift());
  }
  return promise;
}

下面再看一下拦截器的同步执行过程,相对于异步简单很多, 直接遍历执行就可以了。

while (requestInterceptorChain.length) {
  var onFulfilled = requestInterceptorChain.shift();
  var onRejected = requestInterceptorChain.shift();
  try {
    newConfig = onFulfilled(newConfig);
  } catch (error) {
    onRejected(error);
    break;
  }
}

summary

总结一下拦截器的执行过程

interceptor


Author: Maple
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint polocy. If reproduced, please indicate source Maple !
  TOC