axios源码分析与模拟(下)
模拟实现axios取消请求功能
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- CSS -->
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/4.6.2/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N" crossorigin="anonymous">
<!-- <script src="https://cdn.bootcdn.net/ajax/libs/axios/1.7.2/axios.min.js"></script> -->
</head>
<body>
<div class="=container">
<h2 class="page-header">axios取消请求</h2>
<button class="btn btn-primary">发送请求</button>
<button class="btn btn-warning">取消请求</button>
</div>
<script>
//构造函数
function Axios(config){
this.config=config;
}
//原型request方法
Axios.prototype.request=function(config){
return dispatchRequest(config);
}
//dispatchRequest函数
function dispatchRequest(config){
return xhrAdapter(config);
}
//xhrAdapter
function xhrAdapter(config){
//发送AJAX请求
return new Promise((resolve,reject)=>{
//实例化对象
const xhr=new XMLHttpRequest();
//初始化
xhr.open(config.method,config.url);
//发送
xhr.send();
//绑定事件 处理结果
xhr.onreadystatechange=function(){
if(xhr.readyState===4){
//判断成功的条件
if(xhr.status>=200&&xhr.status<300){
//成功的状态
resolve({
//响应状态码
status:xhr.status,
//相应状态字符串
statusText:xhr.statusText
});
}else{
//失败的状态
reject(new Error('请求失败 失败的状态码为 '+xhr.status));
}
}
}
//关于取消请求的处理
if(config.cancelToken){
//对cancelToken对象身上的promise对象指定成功的回调
config.cancelToken.promise.then(value=>{
xhr.abort();
//将整体结果设置为失败
reject(new Error('请求已经被取消'));
})
}
})
}
//创建axios函数
const context=new Axios({});
const axios=Axios.prototype.request.bind(context);
//CancelToken构造函数
function CancelToken(executor){
//声明一个变量
var resolvePromise;
//为实例对象添加属性
this.promise=new Promise((resolve)=>{
//将resolve赋值给resolvePromise
resolvePromise=resolve;
});
//调用executor函数
executor(function(){
//执行resolvePromise函数
resolvePromise();
})
}
//获取按钮 以上为模拟实现请求取消
const btns=document.querySelectorAll('button');
//声明全局变量
let cancel=null;
// 发送请求
btns[0].onclick = function() {
// 检测上一次的请求是否已经完成
if (cancel !== null) {
// 取消上一次的请求
cancel();
}
//创建cancelToken的值
let cancelToken=new CancelToken(function(c){
// 将c的值赋值给cancel
cancel = c;
}
)
axios({
method: 'GET',
url: 'http://localhost:3000/posts',
// 添加配置对象的属性
// cancelToken: cancelToken
}).then(res => {
console.log(res);
// 将cancel的值初始化
cancel = null;
}).catch(error => {
if (axios.isCancel(error)) {
console.log('Request canceled', error.message);
} else {
console.error('Request failed', error);
}
// 将cancel的值初始化
cancel = null;
});
}
// 取消请求
btns[1].onclick = function() {
if (typeof cancel === 'function') {
cancel();
console.log("请求已取消");
cancel = null; // 重置cancel变量
} else {
console.log("没有正在进行的请求");
}
}
</script>
</body>
</html>
这段代码展示了如何使用模拟的 Axios 实现请求取消功能,包括 CancelToken 的实现。下面是对代码的详细解释:
- HTML 结构
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- CSS -->
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/4.6.2/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N" crossorigin="anonymous">
</head>
<body>
<div class="container">
<h2 class="page-header">axios取消请求</h2>
<button class="btn btn-primary">发送请求</button>
<button class="btn btn-warning">取消请求</button>
</div>
</body>
</html>
包含两个按钮:“发送请求”和“取消请求”。
- Axios 构造函数和 request 方法
//构造函数
function Axios(config) {
this.config = config;
}
//原型request方法
Axios.prototype.request = function(config) {
return dispatchRequest(config);
}
Axios 构造函数初始化了一个配置对象 config。
request 方法调用 dispatchRequest 发送请求。
- dispatchRequest 函数
//dispatchRequest函数
function dispatchRequest(config) {
return xhrAdapter(config);
}
dispatchRequest 调用 xhrAdapter 发送 AJAX 请求。
- xhrAdapter 函数
//xhrAdapter
function xhrAdapter(config) {
//发送AJAX请求
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open(config.method, config.url);
xhr.send();
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
resolve({
status: xhr.status,
statusText: xhr.statusText
});
} else {
reject(new Error('请求失败 失败的状态码为 ' + xhr.status));
}
}
};
if (config.cancelToken) {
config.cancelToken.promise.then(value => {
xhr.abort();
reject(new Error('请求已经被取消'));
});
}
});
}
xhrAdapter 发送 AJAX 请求并返回一个 Promise 对象。
处理请求成功和失败的情况。
检查 config 是否包含 cancelToken,如果包含,处理请求取消逻辑。
- 创建 axios 实例
//创建axios函数
const context = new Axios({});
const axios = Axios.prototype.request.bind(context);
创建 Axios 实例并绑定 request 方法。
- CancelToken 构造函数
//CancelToken构造函数
function CancelToken(executor) {
var resolvePromise;
this.promise = new Promise((resolve) => {
resolvePromise = resolve;
});
executor(function() {
resolvePromise();
});
}
CancelToken 用于创建一个取消令牌。
executor 函数接受一个 cancel 函数,并在需要时调用 resolvePromise 取消请求。
- 处理按钮点击事件
const btns = document.querySelectorAll('button');
let cancel = null;
// 发送请求
btns[0].onclick = function() {
if (cancel !== null) {
cancel();
}
let cancelToken = new CancelToken(function(c) {
cancel = c;
});
axios({
method: 'GET',
url: 'http://localhost:3000/posts',
cancelToken: cancelToken
}).then(res => {
console.log(res);
cancel = null;
}).catch(error => {
if (axios.isCancel && axios.isCancel(error)) {
console.log('Request canceled', error.message);
} else {
console.error('Request failed', error);
}
cancel = null;
});
}
// 取消请求
btns[1].onclick = function() {
if (typeof cancel === 'function') {
cancel();
console.log("请求已取消");
cancel = null;
} else {
console.log("没有正在进行的请求");
}
}
获取按钮并添加点击事件处理程序。
在发送请求时,检查并取消上一次未完成的请求。
创建 CancelToken 实例并在请求配置中添加 cancelToken 属性。
在“取消请求”按钮点击时调用 cancel 函数取消请求。
总结
这段代码通过实现一个模拟的 Axios 库,演示了如何使用 CancelToken 来取消请求。具体步骤包括:
创建并绑定 Axios 实例。s
发送 AJAX 请求并处理结果。
实现 CancelToken 构造函数及其逻辑。
在用户交互中处理请求的发送和取消。