关键是在回调执行前显式检查signal.aborted状态:fetch响应后、then/catch入口及异步链各环节均需守卫,避免因竞态导致已取消请求仍处理数据或触发副作用。

在 JavaScript 中,请求取消后不触发回调的关键是:**在请求发起前创建可取消的信号(AbortSignal),并在回调执行前检查信号状态**。原生 fetch 支持 AbortController,但 Promise 本身不可取消,所以必须主动拦截——不能依赖“取消就自动停止回调”,而要靠手动判断。
使用 AbortController + signal 检查中止状态
fetch 返回的 Promise 被拒绝时会抛出 AbortError,但更稳妥的做法是在 then/catch 回调入口处显式检查 signal.aborted:
- 即使 fetch 已完成,若请求中途被取消,你仍可能收到响应;此时需在处理逻辑开头加守卫
- 不要只依赖 catch 捕获 AbortError —— 网络延迟可能导致响应到达时 signal 已 abort,但 Promise 仍 resolve
示例:
const controller = new AbortController();
const { signal } = controller;
fetch('/api/data', { signal })
.then(res => {
// ✅ 关键:响应到达后第一件事就是检查是否已取消
if (signal.aborted) return;
return res.json();
})
.then(data => {
if (signal.aborted) return; // ✅ 再次检查,防止异步链中状态变化
console.log('处理数据:', data);
})
.catch(err => {
if (signal.aborted) return; // ✅ 对应取消错误,直接忽略
console.error('请求失败:', err);
});
// 取消请求
controller.abort();
封装可取消的 Promise 工具函数
避免每次手动检查,可封装一个带信号守卫的 then/catch 辅助函数:
立即学习“Java免费学习笔记(深入)”;
- 返回新 Promise,内部自动跳过已中止的回调执行
- 适用于非 fetch 场景(如自定义定时任务、WebSocket 消息监听等)
示例:
function safeThen(promise, onFulfilled, onRejected, signal) {
return promise.then(
value => signal.aborted ? undefined : onFulfilled?.(value),
reason => signal.aborted ? undefined : onRejected?.(reason)
);
}
// 使用
safeThen(fetch('/api/data', { signal }),
res => res.json(),
err => console.error(err),
signal
).then(data => {
if (!signal.aborted) console.log(data); // 仍需最终守卫,因 then 是微任务
});
清理副作用与资源引用
取消不只是跳过回调,还要防止闭包中持有过期上下文导致内存泄漏或误更新:
- 如果回调里修改了 React state、DOM 元素或全局变量,务必在执行前确认 signal 未中止
- 对 setInterval / setTimeout 等定时器,在 abort 时 clearTimeout / clearInterval
- 对事件监听器(如 WebSocket onmessage),abort 时 removeEventListener
注意:Axios 等库的差异处理
Axios v0.22+ 支持 AbortController,行为与 fetch 一致;旧版本用 CancelToken,但已被废弃。统一推荐用 signal:
- 传入
{ signal }选项后,Axios 会在 cancel 时 reject 并抛出CanceledError - 但仍建议在 then 中检查
signal.aborted,因为 Axios 的 cancel 机制存在竞态窗口
不复杂但容易忽略。核心就一条:把 if (signal.aborted) return 当作回调函数的第一行代码。


















