axios
是一个基于 Promise
的 HTTP
请求库,它的内部实现通过几个核心步骤来发送请求。下面详细解释了这些步骤。
1. axios(url, options) 发生了什么
发送请求流程:
function request(config){
let promise = Promise.resolve(config);
let chains = [dispatchRequest, undefined];// undefined 占位
//调用 then 方法指定回调
let result = promise.then(chains[0], chains[1]);
//返回 promise 的结果
return result;
}
function dispatchRequest(config){
// 发送请求前数据格式的转换 ......
xhrAdapter(config).then(response => {
//响应的结果进行转换处理 ......
return response;
}, error => {
// 发送请求前数据格式的转换 ......
throw error;
});
}
function xhrAdapter(config) {
return new Promise((resolve, reject) => {
//定义 AJAX 请求
let xhr = new XMLHttpRequest();
xhr.open(config.method, config.url);
// 把config上的一些参数、事件监听等,配置到xhr对象上.......
//发送请求
xhr.send();
//监听事件
xhr.onreadystatechange = function(){
if (xhr.readyState !== 4) {
// 如果请求还未完成,则退出
return;
}
if(xhr.readyState === 4){
//判断成功的条件
// xhr.status >= 200 && xhr.status < 300 可以通过自定义传参控制
if(xhr.status >= 200 && xhr.status < 300){
//成功的状态
resolve({
//配置对象
config: config,
//响应体
data: xhr.response,
//响应头
headers: xhr.getAllResponseHeaders(), //字符串 parseHeaders
// xhr 请求对象
request: xhr,
//响应状态码
status: xhr.status,
//响应状态字符串
statusText: xhr.statusText
});
}else{
//失败的状态
reject(new Error({
message: 'Request failed with status code ' + xhr.status,
// 错误信息属性......
}));
}
}
}
});
}
- 返回
Promise
:axios
的请求返回的是一个Promise
。 xhrAdapter
:默认的适配器,负责实际的XMLHttpRequest
请求。它处理请求的发送、响应的处理和错误的捕获。
2. 请求和响应拦截器
axios
允许通过拦截器(interceptors
)来修改请求和响应。我们可以在请求被发送之前对请求进行处理,或在响应到达后对其进行修改。
当我们使用 interceptors.request.use(fulfilled, rejected):
function use(fulfilled, rejected) {
this.handlers.push({
fulfilled: fulfilled,
rejected: rejected,
});
}
在调用 use 方法时,我们把 fulfilled 和 rejected 作为回调添加到拦截器的 handlers 数组中。之后需要用到时会遍历执行。
function(config){
let promise = Promise.resolve(config);
//创建数组,里面存放请求拦截器,XMLHttpRequest 请求和响应拦截器
const chains = [dispatchRequest, undefined];
//处理拦截器
// 遍历请求拦截器的handlers,将回调函数添加到chains前面
this.interceptors.request.handlers.forEach(item => {
chains.unshift(item.fulfilled, item.rejected);
});
// 遍历响应拦截器的handlers,将回调函数添加到 chains 的后面
this.interceptors.response.handlers.forEach(item => {
chains.push(item.fulfilled, item.rejected);
});
//遍历chains中每一个函数(请求拦截器,XMLHttpRequest 请求和响应拦截器)
while(chains.length > 0){
promise = promise.then(chains.shift(), chains.shift());
}
return promise;
}
每次执行都是从chains
数组中去取出两个函数(成功和失败的回调)执行,所以需要[dispatchRequest, undefined]
保证chains
的个数一定是偶数
3. 取消请求
有时我们希望在某些情况下取消发起的 HTTP
请求(例如,用户快速切换页面或模块功能时)。axios
提供了 CancelToken
来实现这一功能。
取消请求的基本用法:
const { cancel, token } = axios.CancelToken.source();
config.cancelToken = token; // 将 cancelToken 添加到请求配置中
axios(config); // 发起请求
// 在需要取消请求时调用 cancel() 方法
cancel();
把 cancel
保存起来,需要取消时调用 cancel()
就可以取消对应的请求
CancelToken.source = function source() {
var cancel;
var token = new CancelToken(function executor(c) {
cancel = c;
});
// 此时已经 cancel=c
return {
token: token,
cancel: cancel,
};
};
// 根据下方代码可知:cancle=c=function() {resolvePromise()}
function CancelToken(executor) {
//声明一个变量,保存到闭包中
var resolvePromise;
// 保存一个promise,后面用来执行回调函数取消请求
this.promise = new Promise((resolve) => {
// 将 resolve 赋值给 resolvePromise
resolvePromise = resolve;
});
//调用 executor 函数
executor(function() {
// resolvePromise 保存在闭包中
resolvePromise();
});
}
为什么 cancel() 可以取消请求?
因为在发送 ajax
请求前,会监听 token.promise
,当我们执行 cancel()
时会改变 promise
的状态,对应的回调函数就会执行,然后取消 ajax
请求
function xhrAdapter() {
//定义 AJAX 请求
let xhr = new XMLHttpRequest();
xhr.open(config.method, config.url);
// 其他请求配置...
if (config.cancelToken) {
// Handle cancellation
config.cancelToken.promise.then(function onCanceled(cancel) {
if (!xhr) {
return;
}
hr.abort(); // 取消请求
reject(cancel); // 触发错误回调
xhr = null; // 清理请求对象
});
}
}
总结
通过了解 axios
的核心原理实现,我们能够更好地掌握请求的处理过程。axios
利用 Promise
链、拦截器机制和取消请求功能,提供了优秀的扩展性。在实际开发中,了解这些实现细节可以帮助我们更好地优化请求逻辑,提升开发效率。
希望这篇文章能帮助你更深入地理解 axios
的工作原理以及如何更高效地利用它进行 HTTP
请求操作✊️✊️