前言
在前端开发中,我们经常遇到需要中途撤回请求的情况(例如:搜索框快速输入、大型文件上传取消、或是 AI 聊天流的即时中断)。传统的 Promise 一旦启动就无法在外部“叫停”,而 AbortController 的出现,完美填补了这一空白。
一、 核心概念与原理
AbortController 是 JavaScript 内置的信号控制对象,它是实现异步操作可控制、可中止的核心。
1. 关键组成部分
-
controller.signal:一个AbortSignal对象实例。它充当“监听器”,将其传递给异步操作后,该操作会持续观察信号状态。 -
controller.abort():触发中止的方法。调用后,signal上的abort事件会被触发,同时将signal.aborted设为true。
二、 基础使用模式
1. 实现步骤
- 使用
new AbortController()生成实例。 - 将实例中的
signal属性传递给需要支持中止的异步 API(如fetch)。 - 在合适的时机调用
controller.abort()即可主动终止。
2. 代码示例
// 1. 创建 AbortController 实例
const controller = new AbortController();
const { signal } = controller;
// 2. 发起请求并绑定信号
fetch("/api/data", { signal })
.then((response) => response.json())
.then((data) => console.log("请求成功:", data))
.catch((err) => {
// 3. 捕获中止错误
if (err.name === "AbortError") {
console.log("主动取消:请求被成功截断");
} else {
console.error("请求失败:", err);
}
});
// 2 秒后主动取消请求
setTimeout(() => {
controller.abort();
}, 2000);
三、 进阶技巧与场景
1. 批量取消请求
如果想同时取消多个相关的请求,可以给这些请求共享同一个 signal。当调用 abort() 时,所有关联的任务都会收到中止信号。
2. 示例
// 使用同一个 AbortController 取消多个请求
const controller = new AbortController();
// 请求1
const request1 = fetch('url1', {
signal: controller.signal
});
// 请求2
const request2 = fetch('url2', {
signal: controller.signal
});
// 请求3
const request3 = fetch('url3', {
signal: controller.signal
});
// 同时取消所有请求
document.getElementById('cancelBtn').addEventListener('click', () => {
controller.abort();
console.log('所有请求已取消');
});
// 等待所有请求
Promise.all([request1, request2, request3])
.then(responses => Promise.all(responses.map(r => r.json())))
.then(data => console.log('所有数据:', data))
.catch(error => {
if (error.name === 'AbortError') {
console.log('请求被取消');
}
});
3. 注意事项
- 兼容性:并非所有 API 都原生支持。目前
fetch、Axios (v0.22+)模块已提供支持。 - 幂等性:
abort()方法只能生效一次。多次调用虽然不会报错,但只有第一次调用会触发中止逻辑。
四、 总结对比
| 特性 | 传统 Promise | 带有 AbortController 的 Promise |
|---|---|---|
| 可控性 | 开启后无法干预 | 可随时通过 abort() 中止 |
| 异常处理 | 只有成功/失败 | 增加 AbortError 类型,方便区分主动取消与网络异常 |
| 应用场景 | 简单的数据获取 | 复杂交互、流式输出、性能调优 |