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
一般都会打印一下里面是什么的吧
结果返回的是个函数,这时你会想怎么不是应该像vue
,jQuery
那样返回一个对象嘛,这不对呀, 那他的create
从哪里来,不急我们像用console.dir
打印一下这个方法里面的属性
这里确实绑定了很多属性,但好像还是找不到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 Axios
了defaults
就是他的配置,也定义了拦截器,最重要的还是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