传送门:
Axios.prototype.request
Axios
类的构造函数:
// /lib/core/Axios.js
function Axios(instanceConfig) {
// 默认配置
this.defaults = instanceConfig;
// 拦截器
this.interceptors = {
// 请求拦截器
request: new InterceptorManager(),
// 响应拦截器
response: new InterceptorManager()
};
}
Axios.prototype.request
方法是Axios
类原型方法中的重中之重。
Axios.prototype.request = function request(config) {
// 用于API中的 axios(config) 或 axios(url[, config])
if (typeof config === 'string') {
config = arguments[1] || {};
config.url = arguments[0];
} else {
config = config || {};
}
// 将传入的配置与默认配置合并
config = mergeConfig(this.defaults, config);
// 设置请求方法
config.method = config.method ? config.method.toLowerCase() : 'get';
// 请求拦截
// 发送请求
// 响应拦截
}
在分析Axios.prototype.request
中拦截器与请求相关代码之前,要先分析拦截器的原理
拦截器的实现
// /lib/core/InterceptorManager.js
function InterceptorManager() {
this.handlers = [];
}
// 将一个拦截器添加到handlers数组
// 对应API中的 axios.interceptors.request.use 与 axios.interceptors.resopnse.use
// 返回拦截器的ID
InterceptorManager.prototype.use = function use(fulfilled, rejected) {
this.handlers.push({
fulfilled: fulfilled,
rejected: rejected
});
return this.handlers.length - 1;
};
// 移除指定ID的拦截器
InterceptorManager.prototype.eject = function eject(id) {
if (this.handlers[id]) {
this.handlers[id] = null;
}
};
// 遍历执行handlers数组中的拦截器,跳过被eject成null的项
InterceptorManager.prototype.forEach = function forEach(fn) {
utils.forEach(this.handlers, function forEachHandler(h) {
if (h !== null) {
fn(h);
}
});
};
module.exports = InterceptorManager;
回到 Axios.prototype.request
Axios.prototype.request = function request(config) {
/* 配置相关代码 */
// 请求链 chain
// 首先加入发送请求的方法和 undefined
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);
});
// 遍历请求链,形成 promise 链
while (chain.length) {
promise = promise.then(chain.shift(), chain.shift());
}
// 返回promise链
return promise;
}
流程图如下:
这里尤其应注意到请求链中请求拦截器的顺序(handlers数组的倒序),在使用axios.interceptors.request.use
时,要留意这一点。
Axios类与入口文件中的axios
另外,Axios
类还有Axios.prototype.get
、Axios.prototype.post
、Axios.prototype.delete
等方法,实际上都是修改了Axios.prototype.request
参数config
中的method
属性。
utils.forEach(['delete', 'get', 'head', 'options'], function forEachMethodNoData(method) {
Axios.prototype[method] = function (url, config) {
return this.request(utils.merge(config || {}, {
method: method,
url: url
}));
};
});
utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
Axios.prototype[method] = function (url, data, config) {
return this.request(utils.merge(config || {}, {
method: method,
url: url,
data: data
}));
};
});
分析完Axios
类,我们再次回到入口文件:
// /lib/axios.js
function createInstance(defaultConfig) {
// 创建一个Axios类的实例,得到一个上下文环境
// 包含defaults配置与拦截器(详见/lib/core/Axios.js)
var context = new Axios(defaultConfig);
// instance是一个函数(request请求方法)
// this绑定到context上下文
var instance = bind(Axios.prototype.request, context);
// 将Axios.prototype的各方法绑定到instance上
// 其中this作用域为context上下文
utils.extend(instance, Axios.prototype, context);
// 将context中的属性(defaults与拦截器)绑定到instance实例中
utils.extend(instance, context);
return instance;
}
var axios = createInstance(defaults);
/* ... */
modules.exports = axios;
现在我们就可以在Axios
类中找到,axios
中的defaults
、interceptors
属性,以及axios()
、axios.get()
、axios.post()
等请求方法的由来。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。