AbortController 通过统一信号管理简化异步任务中断:创建控制器→传入 signal→调用 abort() 触发中止;支持 fetch、自定义 Promise(如 delay)、多任务共享及 async/await 场景。

用 AbortController 简化异步任务中断,核心是统一信号管理:创建控制器 → 传入 signal → 调用 abort() 触发中止逻辑。它让 fetch、setTimeout 模拟、Stream 等都能响应同一中断源,避免手动维护标志位或 clearTimeout 的散乱逻辑。
一、基础用法:配合 fetch 中断网络请求
原生 fetch 支持 signal 选项,接收到 abort 信号后自动拒绝 Promise,并抛出 AbortError。
示例:
const controller = new AbortController();
const signal = controller.signal;
fetch('/api/data', { signal })
.then(res => res.json())
.then(data => console.log(data))
.catch(err => {
if (err.name === 'AbortError') {
console.log('请求已被取消');
} else {
console.error('其他错误:', err);
}
});
// 3 秒后主动取消
setTimeout(() => controller.abort(), 3000);
二、封装可取消的 Promise(如定时器、轮询)
不是所有异步操作原生支持 signal,但你可以用它协调手动清理逻辑。
立即学习“Java免费学习笔记(深入)”;
比如封装一个带中断能力的延时函数:
function delay(ms, signal) {
return new Promise((resolve, reject) => {
if (signal.aborted) {
reject(new DOMException('Aborted', 'AbortError'));
return;
}
const timeoutId = setTimeout(resolve, ms);
signal.addEventListener('abort', () => {
clearTimeout(timeoutId);
reject(new DOMException('Aborted', 'AbortError'));
}, { once: true });
});
}
// 使用
const controller = new AbortController();
delay(5000, controller.signal)
.then(() => console.log('执行完成'))
.catch(err => console.log(err.name)); // 可能是 AbortError
controller.abort(); // 立即中断
三、多个异步任务共享同一个 signal
一个 AbortController 的 signal 可被多个异步操作监听,调用一次 abort() 就能批量中止。
- 适合页面级操作(如离开页面前取消所有待处理请求)
- 适合表单提交时禁用重复点击,同时取消上一次未完成的请求
- 注意:signal 是只读的,不可重用;abort 后再使用会立即触发 reject
四、与 async/await 结合的实用模式
在 async 函数中,建议把 signal 检查提前,并配合 try/catch 处理中止异常。
async function loadData(signal) {
try {
const res = await fetch('/api/items', { signal });
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return await res.json();
} catch (err) {
if (signal.aborted) {
throw new DOMException('加载已取消', 'AbortError');
}
throw err;
}
}
// 调用
const controller = new AbortController();
loadData(controller.signal)
.catch(err => {
if (err.name === 'AbortError') {
console.log('用户取消了加载');
}
});
// 需要时调用 controller.abort()
不复杂但容易忽略:每次新建异步操作都应创建新的 AbortController 实例,不要复用已 abort 的 controller;signal 本身不能触发 abort,只能被监听;真正的中断行为由各 API 内部实现决定,你只需提供信号和响应逻辑。


















