promise本身不支持取消,但可通过abortcontroller实现对fetch等异步操作的中止;关键在于让异步源响应signal信号并主动reject,而非取消promise本身。

Promise 本身不支持取消,但结合 AbortController 可以实现对异步操作(如 fetch)的主动中止。关键在于:不是“取消 Promise”,而是让 Promise 内部的异步源(如网络请求)响应中断信号并提前拒绝。
AbortController 如何与 Promise 配合工作
AbortController 提供一个 signal 对象,它是一个可监听的中断信号。当调用 controller.abort() 时,signal.aborted 变为 true,且触发 abort 事件。原生支持 AbortSignal 的 API(如 fetch)会自动响应这个信号并 reject;自定义 Promise 则需手动检查 signal.aborted 并提前 throw 错误。
在 fetch 请求中直接使用 signal
这是最常见、最简洁的用法。fetch 原生支持 signal 选项:
- 创建
const controller = new AbortController() - 将
controller.signal传入fetch(url, { signal }) - 调用
controller.abort()即可中止请求,此时 fetch 返回的 Promise 会以AbortError拒绝
示例:
const controller = new AbortController();
fetch('/api/data', { signal: controller.signal })
.then(res => res.json())
.catch(err => {
if (err.name === 'AbortError') {
console.log('请求已被取消');
} else {
console.error('其他错误:', err);
}
});
// 3 秒后取消(模拟用户取消)
setTimeout(() => controller.abort(), 3000);
封装支持取消的自定义 Promise
对于不原生支持 AbortSignal 的异步逻辑(比如定时器、WebSocket 连接、或复杂计算),需手动监听 signal 并提前退出:
- 在 Promise 内部监听
signal.onabort或轮询signal.aborted - 一旦检测到中断,立即
reject(new DOMException('Aborted', 'AbortError')) - 注意清理副作用(如清除定时器、关闭连接)
示例(模拟带取消的延时任务):
function delay(ms, signal) {
return new Promise((resolve, reject) => {
// 立即检查是否已中止
if (signal.aborted) {
return reject(new DOMException('Aborted', 'AbortError'));
}
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 => {
if (err.name === 'AbortError') console.log('被取消了');
});
setTimeout(() => controller.abort(), 2000); // 2 秒后取消
注意事项和常见误区
AbortController 不会强制终止 Promise 执行,也不会自动清理你代码中的其他资源。它只是提供一种标准信号机制:
- Promise 一旦 resolve/reject,无法被“撤回”——所以必须在内部逻辑中主动响应 signal
- 多个 Promise 共享同一个 signal 是安全的,abort 会同时影响所有监听它的操作
- 不要重复调用
controller.abort(),多次调用无副作用,但也没必要 - Node.js 15+ 也支持
AbortController,但在更早版本需 polyfill
不复杂但容易忽略:取消的关键永远是你自己在 Promise 内部做判断和处理,而不是依赖 Promise 自身“变取消”。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











