搞明白axios源码,探究配置、拦截器、适配器的执行过程

2023-01-03 0 865

序言

上四节他们单纯地如是说了呵呵 axios 总体读取业务流程和采用操作过程。能确切地介绍到彼时 import axios from axios 后 这另一面究竟做了甚么。因此他们也单纯如是说了两个 axios 究竟是两个甚么类别的统计数据。和为甚么能即能当做方式初始化还能透过第一类的初始化形式初始化这类特性方式

假如没介绍的老师能南西看呵呵上一则该文的如是说,再继续往上看。

这篇他们主要就传授呵呵 axios 中的 实用性、圣夫龙和继续执行链等许多核心理念的机能究竟是是不是运转的。

实用性操作过程

要介绍那个以后,他们先上看呵呵 axios 在采用的这时候一类形式:

axios.create({ …实用性项 })

不晓得我们是不是采用过此种形式,此种形式能让他们传达许多实用性到 axios 的外部,具体内容同时实现如下表所示:

axios.create = function create(instanceConfig) { returncreateInstance(mergeConfig(axios.defaults, instanceConfig)); };

要说,最后又初始化了 createInstance 表达式,再上看呵呵表达式体吧:

function createInstance(defaultConfig) { var context = new Axios(defaultConfig); varinstance = bind(Axios.prototype.request, context);// Copy axios.prototype to instanceutils.extend(instance, Axios.prototype, context);// Copy context to instance utils.extend(instance, context); return instance; }

有两个表达式需要关注呵呵就是 mergeConfig, 那个表达式会把 axios 自带的实用性和他们传入的实用性进行合并,他们传入的实用性会覆盖 axios 自带的实用性,也就是说他们传入的实用性优先级会更高。

由于那个 mergeConfig 表达式体积太大,他们就不细说了,我们有兴趣能看呵呵源代码。

这里要继续说呵呵,他们在发送某个具体内容的请求的这时候也能进行实用性,这样就有三个实用性。

优先级依次是:某个具体内容请求实用性 > 创建实例第一类实用性 > axios 默认实用性

请求操作过程

上节说过,axios能像第一类那样初始化特性方式,如 get、post等,其实最后都会初始化 request 方式,代码如下表所示:

utils.forEach([delete, get, head, options], function forEachMethodNoData(method) { /*eslint func-names:0*/ Axios.prototype[method] = function(url, config) { return this.request(mergeConfig(config || {}, { method: method, url: url, data: (config || {}).data })); }; }); utils.forEach([post, put, patch], function forEachMethodWithData(method) { /*eslint func-names:0*/ Axios.prototype[method] = function(url, data, config) { return this.request(mergeConfig(config || {}, { method: method, url: url, data: data })); }; });

能看出最后都会初始化到 this.request 方式。那他们来重点看呵呵 request方式具体内容做了甚么。

先看呵呵表达式体吧,代码也不是很多:

Axios.prototype.request = function request(config) { /*eslint no-param-reassign:0*/ // Allow for axios(example/url[, config]) a la fetch API if (typeof config === string) { config = arguments[1] || {}; config.url = arguments[0]; } else { config = config || {}; } config = mergeConfig(this.defaults, config); // Set config.method if (config.method) { config.method = config.method.toLowerCase(); } else if (this.defaults.method) { config.method =this.defaults.method.toLowerCase(); } else { config.method = get; } // Hook up interceptors middleware var chain = [dispatchRequest, undefined]; var promise = Promise.resolve(config);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); });while(chain.length) { promise = promise.then(chain.shift(), chain.shift()); }return promise; };

主要就有三点:

1、生成实用性项

2、生成圣夫龙、继续执行链

3、返回继续执行链的结果

下面他们重点如是说呵呵 2 是如何生成圣夫龙和继续执行链的

每个axios实例都会有两个 interceptors 特性,如下表所示:

function Axios(instanceConfig) { this.defaults = instanceConfig; this.interceptors = {request: new InterceptorManager(), response: new InterceptorManager() }; }

interceptors里面存放着 request 圣夫龙和response圣夫龙。InterceptorManager 中有两个 handlers 特性,是两个数组存放着具体内容的圣夫龙,再上看两个比较熟悉的方式:

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

相信我们肯定用过那个 use 方式,那个方式接收两个表达式类别的参数,再封装成两个第一类放到 handlers中。

再回到 request 表达式体中,看呵呵 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); });

透过遍历把 handlers 的圣夫龙都放到两个 chain 中,尤其要注意:this.interceptors.request 那个操作,是把最后的圣夫龙放到 chain的最前面。最后形成以下链接:

搞明白axios源码,探究配置、拦截器、适配器的执行过程

当然这还不是最后的 chain,因为前面

var chain = [dispatchRequest, undefined];

有这样行代码,所以最后的 chain 应该是下面的:

搞明白axios源码,探究配置、拦截器、适配器的执行过程

这才是两个最后的 chain 。也就是说他们继续执行的每个请求都是继续执行了两个链,最后返回了两个 promise第一类,是不是感觉也没那么神秘,看呵呵继续执行代码,很单纯

var promise = Promise.resolve(config); while(chain.length) { promise = promise.then(chain.shift(), chain.shift()); }return promise;

以上便是 axios 发送某个请求的全操作过程,那么接下来他们继续看呵呵究竟是是不是发送的请求。

具体内容请求

从上面他们能看到axios发送的请求就是两个链的继续执行操作过程,除去 request 和 response的圣夫龙不说,他们重点说呵呵:dispatchRequest 那个方式的继续执行操作过程,因为具体内容的请求就是在那个方式中继续执行的。先上看呵呵源代码:

module.exports = function dispatchRequest(config) { throwIfCancellationRequested(config); // Ensure headers existconfig.headers = config.headers || {}; // Transform request data config.data = transformData(config.data, config.headers, config.transformRequest ); // Flatten headersconfig.headers = utils.merge( config.headers.common || {}, config.headers[config.method] || {}, config.headers ); utils.forEach( [delete, get, head, post, put, patch, common], function cleanHeaderConfig(method) { delete config.headers[method]; } ); var adapter = config.adapter || defaults.adapter;return adapter(config).then(function onAdapterResolution(response){ throwIfCancellationRequested(config); // Transform response data response.data = transformData( response.data, response.headers,config.transformResponse ); return response; }, function onAdapterRejection(reason) { if (!isCancel(reason)) { throwIfCancellationRequested(config); // Transform response dataif(reason && reason.response) { reason.response.data = transformData( reason.response.data, reason.response.headers,config.transformResponse ); } } returnPromise.reject(reason); }); };

方式本身并不难理解,处理呵呵请求头然后再透过转换器转呵呵请求统计数据,最后透过两个转接器继续执行请求。下面他们再看呵呵转接器是甚么,看呵呵下面的代码

var adapter = config.adapter || defaults.adapter;

们看呵呵默认的转接器是是不是样的。下面是默认实用性的代码:

adapter: getDefaultAdapter(),

继续看:

function getDefaultAdapter() { var adapter; if (typeof XMLHttpRequest !== undefined) { // For browsers use XHR adapter adapter = require(./adapters/xhr); } else if (typeof process !== undefined && Object.prototype.toString.call(process) === [object process]) { // For node use HTTP adapter adapter = require(./adapters/http); } return adapter; }

看到这里应该大体的有点晓得了吧,其实就是他们平时用的 XMLHttpRequest 第一类,那为甚么还要做两个转接器呢,主要就是因为 axios 不仅仅是一款能用在 浏览器的库,在 node 开发中也能采用,但node中没 XMLHttpRequest第一类,就得透过其它的形式同时实现。本文不涉及 node,所以他们主要就看以下代码

adapter = require(./adapters/xhr);

因为代码比较多,所以这里我用图片的形式展示呵呵:

搞明白axios源码,探究配置、拦截器、适配器的执行过程

到这里,他们才真正看到了熟悉的 XMLHttpRequest第一类。其实axios底层也就是用的 XMLHttpRequest第一类而已,没甚么神秘的。只不过人家封装的很好用起来方便。

其实到这里他们就已经把 axios的总体源代码分析了一次,当然还有很多细节没说到,比如:错误处理,状态码处理等,我们有兴趣的能自己去细读源代码。只有自己阅读一次才能更好的理解 axios的优雅之处。

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务