Article directory
in the first chapter Handwritten axios source code series one: axios core knowledge points In, we know that there are two configuration methods for canceling requests:
- config.cancelToken
- config.signal
Both methods can cancel the request. Next, let's explore the differences between the two methods of canceling the request.
1. Use CancelToken to cancel the request
The way config.cancelToken cancels the request is to encapsulate the CancelToken class, use the publish/subscribe mode to subscribe to the onCanceled method for the sent request, and then execute the onCanceled method to cancel the request when needed.
1. Create the CancelToken.js file
export default class CancelToken {
constructor(executor){
let resolvePromise;
// 给实例对象添加 promise属性
this.promise = new Promise(function promiseExecutor(resolve){
// 暴露 resolve方法,可以在外部执行 resolvePromise方法改变当前 pending状态的 promise为 fulfilled
resolvePromise = resolve;
})
// 调用执行器函数,传入一个函数
executor(function c(){
resolvePromise()
})
// 当 this.promise状态变更时执行取消请求订阅事件
this.promise.then(() => {
const i = this._listeners.length;
// 循环数组倒序执行
while(i-- > 0){
this._listeners[i](); // 执行取消请求 onCanceled方法
}
// 置空 _listeners
this._listeners = null;
})
}
// 订阅事件方法 subscribe
subscribe(listener){
if (this._listeners){
// 向 _listeners中添加监听函数
this._listeners.push(listenner)
} else {
// 创建 this._listeners容器
this._listeners = [listener]
}
}
// 静态方法 source,其实是一个工厂函数
static source(){
let cancel;
// token为 CancelToken的实例对象,带有 subscribe订阅方法
const token = new CancelToken(function executor(c){
cancel = c;
});
return {
token, cancel }
}
}
2. Subscribe to the onCanceled method when sending a request
When will you subscribe to the onCanceled method of the cancellation request?
Sending a request should be coupled with canceling the request, so you should subscribe to the method onCanceled to cancel the current request when sending the request.
The code to send the request is written under xhr.js:
export default function xhrAdapter(config) {
// 返回一个 promise对象
return new Promise((resolve, reject) => {
// 其他代码
// ...
// 发送请求
request.send(config.data || null);
// 订阅取消请求,根据 config中是否配置了 cancelToken字段来判断是否需要取消请求
if (config.cancelToken) {
const onCanceled = () => {
request.abort(); // 中止请求
}
// 订阅取消请求 onCanceled方法
config.cancelToken.subscribe(onCanceled);
}
})
}
2. Use AbortController to cancel the request
The code to cancel the request using AbortController is very simple. It is judged according to whether there is a signal field in the config object. If there is a signal field, the request will be canceled. If not, no action will be taken.
Modify the xhr.js file code:
export default function xhrAdapter(config) {
// 返回一个 promise对象
return new Promise((resolve, reject) => {
// 其他代码
...
// 发送请求
request.send(config.data || null);
// 订阅取消请求,根据 config中是否配置了 cancelToken字段或者 signal字段来判断是否需要取消请求
if (config.cancelToken || config.signal) {
const onCanceled = () => {
request.abort(); // 中止请求
}
// 订阅取消请求 onCanceled方法
config.cancelToken && config.cancelToken.subscribe(onCanceled);
// signal字段判断
if (config.signal){
/**
* const controller = new AbortController()
* signal是 controller.signal对象,带有三个属性
* signal:{
* aborted: false, 通信请求是否被终止(true)或未终止(false),只读属性。
* onabort: null, 监听事件。
* reason: undefined 取消请求原因。
* }
*/
// aborted 字段为 true时直接取消请求,否则添加 abort监听取消事件
config.signal.aborted ? onCanceled() : config.signal.addEventListener("abort", onCanceled);
}
}
})
}
3. Use json-server to test the "cancel request" function code
json-server is a fast-enabled server that can be run locally on the front end and store json data format. It can be said that it is a mock data service that can imitate RESTful API.
1. Install json-server globally
npm i -g json-server
2. Create the db.json file and monitor the file
{
"posts": [
{
"id": 1,
"title": "json-server",
"author": "typicode"
},
{
"id": 2,
"title": "json-server2",
"author": "typicode2"
}
]
}
Listening command:json-server --watch db.json
.
Because we want to test the cancellation request here, we add a delay time to the request for easy operation.
Execute command:json-server --watch -d 2000 db.json
, the request will return response data after a delay of 2s.
3. Create index.html test code
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>axios源码解析</title>
</head>
<body>
<button id="request">请求接口</button>
<button id="cancel">取消请求</button>
<script type="module">
import axios from "./axios.js";
const requestBtn = document.querySelector("#request");
const cancelBtn = document.querySelector("#cancel");
let source = null;
// let controller = null
requestBtn.addEventListener("click", function () {
// controller = new AbortController();
source = axios.CancelToken.source();
// 发送请求
axios({
method: "get",
url: "http://localhost:3000/posts",
// signal: controller.signal,
cancelToken: source.token
}).then(response => {
console.log(response);
})
});
// 取消请求
cancelBtn.addEventListener("click", function () {
// controller.abort();
source.cancel();
});
</script>
</body>
</html>