阅读 318

Axios运行过程的一个解析(axios实现原理)

前言

之前在写小程序的时候就觉得没有拦截器很不方便,于是就看了看源码,这里只是针对性的去看了解axios的执行过程,拦截器怎么写的,这篇文章的分析只是说axios的一些运行过程,如果想了解全面点,可以看这里,我觉得写得还可以

axios的使用

import axios from "axios"; // 创建一个axios实例 const service = axios.create({   timeout: 6000, }) // 设置请求拦截 service.interceptors.request.use(config => {   return config }, error => {   return Promise.reject(error) }) // 设置响应拦截 service.interceptors.response.use(res => {   return res }, err => {   return Promise.reject(err) }) service({     url: 'xxx/xxx',     method: 'post',     data }) 复制代码

我们从这种axios.create的创建方式来分析执行过程

从入口出发

node__module里面找到axios/lib/axios这里是创建的入口,当我们想要了解axios一般都会打印一下里面是什么的吧

warp.png

结果返回的是个函数,这时你会想怎么不是应该像vue,jQuery那样返回一个对象嘛,这不对呀, 那他的create从哪里来,不急我们像用console.dir打印一下这个方法里面的属性

dir.png

这里确实绑定了很多属性,但好像还是找不到create,没关系,我们来看看源码

// lib/axios.js 'use strict'; var utils = require('./utils'); var bind = require('./helpers/bind'); var Axios = require('./core/Axios'); var mergeConfig = require('./core/mergeConfig'); var defaults = require('./defaults'); /**  * Create an instance of Axios  * 第二步:创建一个axios实例  * @param {Object} defaultConfig The default config for the instance  * @return {Axios} A new instance of Axios  */ function createInstance(defaultConfig) {   // 从这里一开始就创建了一个实例   var context = new Axios(defaultConfig);   // 第三步: 外面serve()执行的就是这个request   var instance = bind(Axios.prototype.request, context);      --------- 代码跳转   // lib/helpers/bind.js   // 调用createInstance(defaults)时候就返回wrap方法 所以在打印的时候看到的就是这个   function bind(fn, thisArg) {       return function wrap() {         var args = new Array(arguments.length);         for (var i = 0; i < args.length; i++) {           args[i] = arguments[i];         }         return fn.apply(thisArg, args);       }; };  ---------          // Copy axios.prototype to instance 继承context   utils.extend(instance, Axios.prototype, context);   // Copy context to instance 继承context   utils.extend(instance, context);   // 使用create递归createInstance方法   // 合并参数 重新创建实例   instance.create = function create(instanceConfig) {     return createInstance(mergeConfig(defaultConfig, instanceConfig));   };   return instance; // 返回一个函数 } // Create the default instance to be exported // 执行 request // 第一步:一开始就创建实例暴露出去了 所以打印的时候就看到了axios是个函数 var axios = createInstance(defaults); // Expose Axios class to allow class inheritance axios.Axios = Axios; // Expose Cancel & CancelToken axios.Cancel = require('./cancel/Cancel'); axios.CancelToken = require('./cancel/CancelToken'); axios.isCancel = require('./cancel/isCancel'); axios.VERSION = require('./env/data').version; // Expose all/spread axios.all = function all(promises) {   return Promise.all(promises); }; axios.spread = require('./helpers/spread'); // Expose isAxiosError axios.isAxiosError = require('./helpers/isAxiosError'); module.exports = axios; // Allow use of default import syntax in TypeScript module.exports.default = axios; 复制代码

request.js

然后进入lib/core/Axios核心库,上面已经new Axiosdefaults就是他的配置,也定义了拦截器,最重要的还是request方法

// lib/core/Axios.js 'use strict'; var utils = require('./../utils'); var buildURL = require('../helpers/buildURL'); var InterceptorManager = require('./InterceptorManager'); var dispatchRequest = require('./dispatchRequest'); var mergeConfig = require('./mergeConfig'); var validator = require('../helpers/validator'); var validators = validator.validators; /**  * Create a new instance of Axios  *  * @param {Object} instanceConfig The default config for the instance  */ function Axios(instanceConfig) {   this.defaults = instanceConfig;   // 拦截器   this.interceptors = {     request: new InterceptorManager(),     response: new InterceptorManager()   }; } /**  * Dispatch a request  *   * @param {Object} config The config specific for this request (merged with this.defaults)  */ 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';   }   var transitional = config.transitional;   if (transitional !== undefined) {     validator.assertOptions(transitional, {       silentJSONParsing: validators.transitional(validators.boolean),       forcedJSONParsing: validators.transitional(validators.boolean),       clarifyTimeoutError: validators.transitional(validators.boolean)     }, false);   } ----------------上面可以不用管 都是些边界 合并参数问题   // 这里存放的是请求拦截的处理函数   var requestInterceptorChain =  [];      var synchronousRequestInterceptors = true;       // 这个forEach执行的是new InterceptorManager()里面的方法   // 作用是 把unshiftRequestInterceptors这个方法作为回调参数 获取interceptor   // interceptor就是拦截器的对象   this.interceptors.request.forEach(     function unshiftRequestInterceptors(interceptor) {      // 边界问题       if (typeof interceptor.runWhen === 'function' && interceptor.runWhen(config) === false) {       return;     }     // synchronousRequestInterceptors=false     synchronousRequestInterceptors = synchronousRequestInterceptors && interceptor.synchronous;     // 每个use放到一个requestInterceptorChain数组里     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) {       // dispatchRequest是发送请求的方法     var chain = [dispatchRequest, undefined];               // 向chain开头添加resolve reject回调      Array.prototype.unshift.apply(chain, requestInterceptorChain);     // 拼接响应resolve reject回调      //  [requestInterceptorChain,dispatchRequest, undefined,requestInterceptorChain]     chain = chain.concat(responseInterceptorChain);          promise = Promise.resolve(config);     while (chain.length) {       // 执行then 获取config 传给 resolve reject       promise = promise.then(chain.shift(), chain.shift());     }          return promise;   }   var newConfig = config;   while (requestInterceptorChain.length) {     var onFulfilled = requestInterceptorChain.shift();     var onRejected = requestInterceptorChain.shift();     try {       newConfig = onFulfilled(newConfig);     } catch (error) {       onRejected(error);       break;     }   }   try {     promise = dispatchRequest(newConfig);   } catch (error) {     return Promise.reject(error);   }   while (responseInterceptorChain.length) {     promise = promise.then(responseInterceptorChain.shift(), responseInterceptorChain.shift());   }   return promise; }; //...省略 module.exports = Axios; 复制代码

InterceptorManager拦截器

'use strict'; var utils = require('./../utils'); function InterceptorManager() {   this.handlers = []; } /**  * Add a new interceptor to the stack  * 第一步:使用use的时候会把fulfilled,rejected的处理函数push到一个数组里面  * @param {Function} fulfilled The function to handle `then` for a `Promise`  * @param {Function} rejected The function to handle `reject` for a `Promise`  *  * @return {Number} An ID used to remove interceptor later  */ 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; }; /**  * Remove an interceptor from the stack  *  * @param {Number} id The ID that was returned by `use`  */ InterceptorManager.prototype.eject = function eject(id) {   if (this.handlers[id]) {     this.handlers[id] = null;   } }; /**  * Iterate over all the registered interceptors  * 第二步:循环this.handlers获取里面的对象  * This method is particularly useful for skipping over any  * interceptors that may have become `null` calling `eject`.  *  * @param {Function} fn The function to call for each interceptor  */ InterceptorManager.prototype.forEach = function forEach(fn) {   utils.forEach(this.handlers, function forEachHandler(h) {     // h -> this.handlers里面的 {fulfilled,rejected}     if (h !== null) {       fn(h);     }   }); }; module.exports = InterceptorManager; 复制代码

一个基本的流程图就是这样

流程图

写着最后

语言组织可能不太好,但是这也算是我个人的一个理解,路还很长,一个小目标一步一步来实现就好了


作者:呆呆兽的猫猫
链接:https://juejin.cn/post/7046961106807914532


文章分类
代码人生
文章标签
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐