AbortController
和 Axios
的 CancelToken
都是用于取消请求的机制,但它们有一些重要的区别,尤其是在使用场景和实现方式上。以下是对这两者的详细比较:
1. AbortController
简介
AbortController
是一种原生的浏览器 API,它允许你通过 AbortController
对象控制一个或多个 Fetch
请求和其他支持该信号的操作。
使用示例
const controller = new AbortController();
const signal = controller.signal;
fetch('/some-url', {
signal })
.then(response => response.json())
.then(data => console.log(data))
.catch(error => {
if (error.name === 'AbortError') {
console.log('Request was aborted');
} else {
console.error('Fetch error:', error);
}
});
// 取消请求
controller.abort();
优点
- 标准化:
AbortController
是现代浏览器的标准 API,并且与 Fetch API 紧密集成。 - 多用途:不仅可用于取消网络请求,还可以取消其他异步操作,只要这些操作支持信号参数。
- 广泛支持:越来越多的浏览器和框架开始支持
AbortController
。
缺点
- 相对较新:在某些旧版浏览器中可能不支持,需要使用 polyfill。
- 不兼容性:需要确保你的 HTTP 库(如 Axios)可以兼容
AbortController
。
2. Axios
的 CancelToken
简介
CancelToken
是 Axios 提供的一种取消请求的机制,它允许你通过 CancelToken
对象取消特定的 Axios 请求。
使用示例
const CancelToken = axios.CancelToken;
let cancel;
axios.get('/some-url', {
cancelToken: new CancelToken(function executor(c) {
cancel = c;
})
})
.then(response => {
console.log(response.data);
})
.catch(thrown => {
if (axios.isCancel(thrown)) {
console.log('Request canceled', thrown.message);
} else {
console.error('Axios error:', thrown);
}
});
// 取消请求
cancel('Operation canceled by the user.');
优点
- 内置功能:直接集成到 Axios 中,无需额外配置。
- 简单易用:API 设计简单,易于理解和使用。
缺点
- 局限性:只能用于取消 Axios 的请求,不能用于其他异步操作。
- 废弃通知:Axios 团队宣布将在未来的版本中废弃
CancelToken
,建议用户转向使用AbortController
。
总结
AbortController
- 适用范围:广泛,除了网络请求,还可以用于其他支持信号的异步操作。
- 标准化:现代浏览器的标准 API。
- 兼容性:需要确保所有相关库都支持
AbortController
。
CancelToken
- 适用范围:专用于 Axios 请求取消。
- 简单易用:直接集成到 Axios 中,但将来会被废弃。
推荐使用 AbortController
鉴于 CancelToken
将在未来版本中被废弃,推荐使用 AbortController
进行请求取消。以下是如何在 Axios 中使用 AbortController
:
import axios from 'axios';
const controller = new AbortController();
axios.get('/some-url', {
signal: controller.signal
})
.then(response => {
console.log(response.data);
})
.catch(error => {
if (error.name === 'AbortError') {
console.log('Request was aborted');
} else {
console.error('Axios error:', error);
}
});
// 取消请求
controller.abort();
更新你的 AxiosCanceler
实现
以下是使用 AbortController
更新你的 AxiosCanceler
实现的示例:
import {
AxiosRequestConfig } from 'axios';
// 用于存储每个请求的标识和取消函数
const pendingMap = new Map<string, AbortController>();
const getPendingUrl = (config: AxiosRequestConfig) => [config.method, config.url].join('&');
export class AxiosCanceler {
// 添加请求(只请求第一次)
public addPending(config: AxiosRequestConfig): void {
const url = getPendingUrl(config);
if (!pendingMap.has(url)) {
// 如果当前请求不在等待中,将其添加到等待中
const controller = new AbortController();
config.signal = config.signal || controller.signal;
pendingMap.set(url, controller);
}
// 如果存在相同URL的请求,则什么都不做
}
// 移除请求
public removePending(config: AxiosRequestConfig) {
const url = getPendingUrl(config);
if (pendingMap.has(url)) {
// 如果当前请求在等待中,取消它并将其从等待中移除
const abortController = pendingMap.get(url);
if (abortController) {
abortController.abort();
}
pendingMap.delete(url);
}
}
// 清空所有请求
public removeAllPending() {
pendingMap.forEach((controller) => {
controller.abort();
});
pendingMap.clear();
}
}
这种方法使用了现代浏览器的标准 API,具有更大的灵活性和广泛的适用性。