JavaScript 请求取消核心是 AbortController,通过注入 signal 实现 fetch 等 API 的中止;需每次请求新建 controller,封装函数暴露 cancel 方法,并在组件卸载时及时调用。

JavaScript 中实现请求取消,核心是利用 AbortController,它提供统一的中止信号机制,适用于 fetch、XMLHttpRequest(需手动适配)以及部分现代 API(如 stream.read())。编写通用的请求取消包装函数,关键是把 AbortSignal 注入请求逻辑,并暴露取消能力。下面给出简洁、可复用、贴近实际场景的写法。
基础版:包装 fetch 的通用取消函数
这是最常用、最轻量的封装,返回带 cancel 方法的对象:
function cancellableFetch(url, options = {}) {
const controller = new AbortController();
const signal = controller.signal;
const promise = fetch(url, {
...options,
signal, // 自动注入中止信号
});
return {
promise,
cancel: () => controller.abort(),
};
}
// 使用示例:
const req = cancellableFetch('/api/data', { method: 'GET' });
req.promise
.then(res => res.json())
.then(data => console.log(data))
.catch(err => {
if (err.name === 'AbortError') {
console.log('请求已被取消');
} else {
console.error('请求失败:', err);
}
});
// 后续可随时调用:
// req.cancel(); // 立即中止请求
增强版:支持 Promise 链式取消 + 自动清理
基础版在 Promise 已 resolve/reject 后调用 cancel() 不报错但无意义。增强版确保只在 pending 状态下生效,并防止重复 abort:
function cancellablePromise(promiseFactory) {
const controller = new AbortController();
let isAborted = false;
const promise = Promise.resolve()
.then(() => {
if (isAborted) throw new DOMException('AbortError', 'AbortError');
return promiseFactory(controller.signal);
});
return {
promise,
cancel() {
if (!isAborted) {
isAborted = true;
controller.abort();
}
},
};
}
// 使用示例(适配 fetch):
const req = cancellablePromise(signal =>
fetch('/api/data', { signal })
);
兼容旧环境:为 XMLHttpRequest 添加取消能力
若需支持不支持 AbortController 的老浏览器(如 IE),可手动模拟取消逻辑:
立即学习“Java免费学习笔记(深入)”;
- 创建
XMLHttpRequest实例并监听状态变化 - 在
cancel()中调用xhr.abort() - 在 Promise 中捕获
abort事件或检查xhr.readyState === 0
注意:这种写法无法真正“中断”已发出的网络请求(底层 TCP 连接仍存在),但能阻止回调执行、释放 JS 层资源,行为上等效于取消。
进阶建议:与 React / Vue 等框架集成时的注意事项
- 在组件卸载(如
useEffect cleanup或onBeforeUnmount)时务必调用cancel(),避免 setState on unmounted component 错误 - 不要把
cancel存在闭包里反复调用——每次请求应新建 controller - 避免将
signal透传给业务层;封装函数内部处理信号注入,保持调用简洁 - 如需超时控制,可组合使用:
controller.timeout = setTimeout(() => controller.abort(), 5000)(注意 clearTimeout 清理)
不复杂但容易忽略:AbortController 是一次性对象,不能复用;每个请求必须新建实例。只要遵循「创建 → 注入 signal → 暴露 cancel → 及时调用」这个流程,就能稳定支撑各类异步取消场景。


















