abortcontroller 是现代浏览器中取消 fetch 请求的标准方法,通过 signal 传入 fetch 并调用 abort() 实现中断,被取消的请求会以 aborterror 拒绝;可封装为返回 promise 和 cancel 方法的工具函数,并注意 react 卸载时及时清理。

Fetch 本身不支持直接取消请求,但可以通过 AbortController 实现标准、兼容性好且语义清晰的中断机制。
使用 AbortController 主动终止请求
这是现代浏览器(Chrome 65+、Firefox 57+、Safari 12.1+)推荐的标准方式。核心是创建一个控制器实例,将其 signal 传入 fetch 选项,再在需要时调用 abort() 方法。
- 创建
AbortController实例,获取其signal - 将
signal作为signal属性传入 fetch 的 options 对象 - 调用
controller.abort()即可中断正在进行的 fetch 请求 - 被中断的 fetch 会立即 reject,错误类型为
DOMException,name为"AbortError"
示例:
const controller = new AbortController();
const { signal } = controller;
fetch('/api/data', { signal })
.then(response => response.json())
.then(data => console.log(data))
.catch(err => {
if (err.name === 'AbortError') {
console.log('请求已被取消');
} else {
console.error('请求失败:', err);
}
});
// 3 秒后取消请求
setTimeout(() => controller.abort(), 3000);
封装可取消的 fetch 工具函数
为避免重复写 controller 和错误处理,可封装成通用函数,支持传入超时或手动取消能力。
- 返回一个对象,包含
promise和cancel方法 - 内部自动创建 AbortController,暴露 cancel 接口
- 支持设置超时时间,超时自动 abort
- 注意:多次调用
cancel()不会报错,但只有第一次生效
简易封装示例:
function cancellableFetch(url, options = {}) {
const controller = new AbortController();
const signal = controller.signal;
const promise = fetch(url, { ...options, signal })
.then(res => {
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
});
return {
promise,
cancel: () => controller.abort()
};
}
// 使用
const { promise, cancel } = cancellableFetch('/api/user');
promise.then(data => console.log(data));
setTimeout(cancel, 2000); // 2秒后取消
与 Promise.race 配合实现超时控制
虽然 AbortController 更推荐,但有时需兼容旧环境或组合逻辑,可用 Promise.race + 自定义 reject 实现超时中断(注意:这不会真正终止网络请求,仅拒绝 Promise)。
-
Promise.race在任一 Promise settle 后即返回结果 - 构造一个延迟 reject 的 Promise 模拟超时
- ⚠️ 注意:该方式无法真正中止底层 HTTP 请求,只是提前结束 JS 层等待
- 适合简单场景;生产环境优先用 AbortController
示例(仅作对比参考):
function timeoutFetch(url, timeout = 5000) {
const controller = new AbortController();
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => {
controller.abort();
reject(new Error('请求超时'));
}, timeout);
});
return Promise.race([
fetch(url, { signal: controller.signal }).then(r => r.json()),
timeoutPromise
]);
}
注意事项与常见坑点
实际使用中容易忽略的关键细节:
- 已 resolve 或 reject 的 fetch Promise 不能再被 abort —— abort 只对「进行中」请求有效
- 同一个
signal不能复用,每次新请求必须新建AbortController - React 等框架中,在组件卸载时务必调用
abort(),防止 setState on unmounted component - 服务端可能仍会处理完请求(如 Node.js 中 req 事件不会因 client abort 自动停止),需服务端配合监听
req.aborted
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











