当前位置 : 首页 > 保养数据

Axios核心原理:Promise链串联请求与拦截器

<|begin▁of▁sentence|># 1. 前言 在之前的文章中,我们介绍了`axios`的拦截器,并使用`Promise`实现了一个简单版的拦截器。在文中还提到了`axios`的核心工作原理:**`axios`的核心是`Promise`,然后使用`Promise`的特性来处理请求和响应拦截器`。`** 那么,`axios`内部究竟是如何实现整个`Promise`链的?又是如何将请求拦截器和响应拦截器以及`axios`请求串联成一个完整的`Promise`链?本篇文章将从源码角度来探索`axios`的核心工作原理。 # 2. 从使用方式入手 在探索源码之前,我们先回忆一下`axios`是如何使用的: ```javascript // 添加请求拦截器 axios.interceptors.request.use( function (config) { // 在发送请求之前做些什么 return config; }, function (error) { // 对请求错误做些什么 return Promise.reject(error); } ); // 添加响应拦截器 axios.interceptors.response.use( function (response) { // 对响应数据做点什么 return response; }, function (error) { // 对响应错误做点什么 return Promise.reject(error); } ); // 发送请求 axios({ method: "get", url: "http://www.baidu.com", }) .then((res) => { console.log(res); }) .catch((err) => { console.log(err); }); ``` 从上面的代码中我们可以看到,当我们发送请求时,是先添加了请求拦截器,然后又添加了响应拦截器,最后再执行`axios`请求。那么,整个`Promise`链又是如何将这些串联起来的呢? # 3. 源码探索 为了搞清楚这个问题,我们直接上源码,源码位置在`lib/core/Axios.js`中,找到`Axios.prototype.request`方法,该方法就是`axios`发送请求的入口,代码如下: ```javascript Axios.prototype.request = function request(config) { // 代码省略... // 处理config,判断参数,代码省略... // 将拦截器数组和发送请求的数组拼接成一个数组 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(function pushResponseInterceptors( interceptor ) { responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected); }); var promise; 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; } // 代码省略... }; ``` 从上面代码中可以看到,`request`方法内部定义了两个数组:`requestInterceptorChain`和`responseInterceptorChain`,分别用来存放请求拦截器和响应拦截器。然后通过`forEach`方法遍历`this.interceptors.request`和`this.interceptors.response`,将每个拦截器的`fulfilled`和`rejected`方法分别`unshift`和`push`到对应的数组中。 接下来,定义了一个`promise`变量,然后判断` synchronousRequestInterceptors`是否为`true`,这个变量是用来判断请求拦截器是否是同步的,默认是`true`,如果请求拦截器中有异步的,那么就会进入`if`分支。 在`if`分支中,定义了一个`chain`数组,初始值为`[dispatchRequest, undefined]`,其中`dispatchRequest`是发送请求的方法,`undefined`是为了占位,因为`then`方法需要两个参数,一个是成功的回调,一个是失败的回调。 然后,使用`Array.prototype.unshift.apply(chain, requestInterceptorChain)`将请求拦截器数组`requestInterceptorChain`中的方法`unshift`到`chain`数组的前面。 接着,使用`chain = chain.concat(responseInterceptorChain)`将响应拦截器数组`responseInterceptorChain`中的方法`concat`到`chain`数组的后面。 此时,`chain`数组的结构如下: ```javascript [ requestInterceptorChain[0], // 请求拦截器成功的回调 requestInterceptorChain[1], // 请求拦截器失败的回调 ..., dispatchRequest, // 发送请求的方法 undefined, // 占位 responseInterceptorChain[0], // 响应拦截器成功的回调 responseInterceptorChain[1], // 响应拦截器失败的回调 ..., ] ``` 然后,使用`Promise.resolve(config)`创建一个`Promise`实例,并将`config`作为参数传入。 接下来,使用`while`循环,每次从`chain`数组中取出两个元素,一个是成功的回调,一个是失败的回调,然后调用`promise.then`方法,将这两个回调传入。 最后,返回`promise`。 这样,整个`Promise`链就串联起来了。 # 4. 流程图 为了更直观的理解整个`Promise`链的串联过程,我们可以画一个流程图: ![](~@/axios/05/01.png) # 5. 总结 通过本文的学习,我们了解了`axios`的核心工作原理:**`axios`的核心是`Promise`,然后使用`Promise`的特性来处理请求和响应拦截器。** 并且通过源码分析,我们知道了`axios`内部是如何将请求拦截器和响应拦截器以及`axios`请求串联成一个完整的`Promise`链的。 希望本文能够帮助你更好的理解`axios`的工作原理。

栏目列表