axios源码分析
基本使用
了解一款常见的网络框架原理axios
,通过适配器模式,在浏览器封装xhr
,在node封装http
模块,上层的调用保持一致。
需要掌握
- 请求拦截器和响应拦截器的实现
- 基于axios进行二次封装,实现业务特定需求
- 并发限制
- 用户鉴权认证、JWT
常见问题
- 如何取消请求:构造cancelToken然后传入请求配置参数,然后可以在发送请求之前手动调用该CancelToken对象的calcel方法来抛出异常,取消本次请求,Promise本身是无法取消的
- 拦截器是如何实现的:先构造一个队列,将请求拦截器依次放在队列头部,响应拦截器一次放在队列尾部,中间是
dispatchRequest
方法,然后将该队列构造为promise链式调用。
拦截器
构造函数
function Axios(instanceConfig) {
this.defaults = instanceConfig;
this.interceptors = {
request: new InterceptorManager(),
response: new InterceptorManager()
};
}
然后来看看`InterceptorManager`这个拦截器管理类
function InterceptorManager() {
this.handlers = [];
}
// 添加拦截器
InterceptorManager.prototype.use = function use(fulfilled, rejected) {
this.handlers.push({
fulfilled: fulfilled,
rejected: rejected
});
return this.handlers.length - 1;
};
// 取消拦截器
InterceptorManager.prototype.eject = function eject(id) {
if (this.handlers[id]) {
this.handlers[id] = null;
}
};
// 遍历拦截器
InterceptorManager.prototype.forEach = function forEach(fn) {
utils.forEach(this.handlers, function forEachHandler(h) {
if (h !== null) {
fn(h);
}
});
};
核心方法`Axios.prototype.request`
Axios.prototype.request = function request(config) {
// ...初始化配置
// 构建任务链
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;
};
理解拦截器也十分容易了
// 原始的接口
function dispatchRequest(config){
let res = {
params: config,
code: 200,
data: "hello response",
}
// 省略实际接口请求逻辑
return Promise.resolve(res);
}
var chain = [dispatchRequest, undefined];
// 请求配置
var config = {
headers: {
'x-token': 'xxxx12token'
},
params: {
id: 1
}
};
var promise = Promise.resolve(config);
var interceptors = {
request: [
{
fulfilled(config) {
console.log(config);
return config;
},
rejected() {
console.log("request reject");
}
}
],
response: [
{
fulfilled(res) {
console.log(res)
},
rejected() {
console.log("response reject");
}
}
]
};
interceptors.request.forEach(function unshiftRequestInterceptors(
interceptor
) {
chain.unshift(interceptor.fulfilled, interceptor.rejected);
});
interceptors.response.forEach(function pushResponseInterceptors(
interceptor
) {
chain.push(interceptor.fulfilled, interceptor.rejected);
});
while (chain.length) {
promise = promise.then(chain.shift(), chain.shift());
}
promise.then(res=>{
console.log(res)
})