Axios是基于promise的网络请求库,其在node中会使用http对象发起网络请求,在浏览器环境中会使用XHR对象发起网络请求。
本文要探究的是interceptor的执行顺序与cancel取消请求的原理。最后封装一个可以后一个请求可以打断前一个请求的方法。
interceptor的请求顺序
案例:
在使用use方法设置多个拦截器,其注册属性如下
request1 -> request2 -> response1-> response2
存入数组
拦截器在理论上可以有无数个,这是因为axios内部使用数组保存了每一个拦截器。其使用user方法将拦截器存入数组中,源码如下。
拦截器在使用的时候是 axios.interceptors.request.use/ axios.interceptors.response.use
request/response为InterceptorManager的实例,因此可以使用实例上的user方法。

可以看出use方法很简单,只是把fulfilled方法与rejected方法出入数组中

从数组中取出
可以看出内部使用了名为chain的数组,在发起网络请求前,取出interceptors对象中request和response实例中存储的fulfilled与rejected函数。
注意:请求拦截器使用的是unshift方法;响应拦截器使用的是push方法

链式调用及顺序
chain数组中使用了undefinded占位,这因为在后面promise的链式调用中是用了shift方法从数组中取值,如果不使用undefined占位,会导致错位产生。
其中dispatchRequest是发送网络请求的核心,其会调用adapter对象发送网络请求

adapter方法
由于adapter方法太长了,这里就截取了部分代码,其原理也很简单,就是返回一个promise实例。
下面是其中一个代码片段,这里判断了cancelToken

那么文章一开始的执行顺序就有了答案:
request2 -> request1 -> response1-> response2
cancel取消请求
上方的代码片段中有对cancelToken的判断
那么就开始分析代码片段
config.cancelToken.promise.then ...
这里的出处如下:
1. axios对象上添加cancelToken方法,

2. new 一个cancelToken
可以在拦截器中设置config的cancelToken属性,也可以直接创建axios实例的时候设置
这里是在拦截器中设置

3. 执行promise链
在链式调用的时候 dispatchRequest调用之前,会对根据config对网络请求进行一列的配置。
到了dispatchRquest的时候会调用封装好的adapter方法。
在adapter方法中,会有对cancelToken的处理。
首先看一下cancelToken方法的封装

可以看出这里给CancelToken的实例上有一个promise属性,其值为一个promise实例。在这里使用了resolvePromise变量引用了resolve函数,因此来在外部控制这个promise实例的状态。
在配置config.cancelToken的时候会newCancelToken函数,使得config.cancelToken的值为一个新的promise实例(非chain数组中的onfulfilled, onrejected函数)。
这个新的promise实例会影响chain数组产生的prmoise链的执行状态。
c => cancel = c 的理解
cancelToken内部有如下executor函数
executor(function cancel(message){
// 略。。。
})
传入c => cancel =c 的函数为executor,那么这样就可以把内部的cancel函数“取出”到外部,然后由执。
cancel函数内部会使用resolvePromise来决议这个新prmoise的状态,如果一直不调用cancel不会影响后续的终止动作,如果调用了就会终止网络请求。
其流程如下:
axios封装网络请求的中断
用后面的网络请求终止前面的网络请求

最后
cancelToken函数设计很巧妙,了解了cancelToken的工作流程之后会对promise有更加深入的了解。