前言
之前在写小程序的时候就觉得没有拦截器很不方便,于是就看了看源码,这里只是针对性的去看了解axios的执行过程,拦截器怎么写的,这篇文章的分析只是说axios的一些运行过程,如果想了解全面点,可以看这里,我觉得写得还可以
axios的使用
// 这里引入axios的时候就已经创建了axiso的实例了,并且返回一个函数
import axios from "axios";
// 创建一个axios实例
// 使用create会把参数进行合并
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;
一个基本的流程图就是这样
写着最后
语言组织可能不太好,但是这也算是我个人的一个理解,路还很长,一个小目标一步一步来实现就好了