AbortController 是用于主动中止异步操作的标准 API,核心是新请求发起时自动取消上一个未完成请求,适用于搜索联想、分页加载等场景,并可扩展至定时器、WebSocket 等非 fetch 操作。

AbortController 是 JavaScript 中用于主动中止异步操作(如 fetch、setTimeout、Promise 等)的标准 API。处理“并发冲突自动取消”,核心思路是:**当新请求发起时,自动取消上一个尚未完成的请求**,避免旧响应覆盖新请求结果或造成状态错乱。
用 AbortController 实现请求级自动取消
这是最常见场景,比如搜索框输入联想、下拉刷新、分页加载等。每次新请求发出前,先调用 abort() 终止上一次未完成的请求:
- 为每次请求创建独立的
AbortController实例 - 将
controller.signal传入fetch的signal选项 - 在发起新请求前,检查并调用上一个 controller 的
abort()
示例代码:
let currentController = null;
async function fetchSearchResults(query) {
// 取消上一次请求(如果存在且未完成)
if (currentController) currentController.abort();
// 创建新控制器
currentController = new AbortController();
try {
const res = await fetch(`/api/search?q=${query}`, {
signal: currentController.signal
});
const data = await res.json();
return data;
} catch (err) {
if (err.name === 'AbortError') {
// 被主动取消,静默忽略(不报错)
return null;
}
throw err;
}
}
封装成可复用的取消钩子(React 场景)
在 React 中,常配合 useEffect 和依赖变化实现自动取消。关键点是:每次 effect 执行时,清理函数中调用 abort(),确保组件卸载或依赖变更时旧请求被终止:
立即学习“Java免费学习笔记(深入)”;
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 在
useEffect内部新建AbortController - 把
fetch或其他异步操作放在 effect 中,并传入signal - 返回的清理函数调用
controller.abort()
示例(React 函数组件):
function SearchList({ query }) {
const [results, setResults] = useState([]);
useEffect(() => {
const controller = new AbortController();
async function load() {
try {
const res = await fetch(`/api/search?q=${query}`, {
signal: controller.signal
});
const data = await res.json();
setResults(data);
} catch (err) {
if (err.name !== 'AbortError') {
console.error('请求失败:', err);
}
}
}
if (query) load();
// 组件更新或卸载时自动取消
return () => controller.abort();
}, [query]);
return <ul>{results.map(item => <li key={item.id}>{item.name}</li>)}</ul>;
}
扩展支持非 fetch 操作(如定时器、自定义 Promise)
AbortSignal 不仅用于 fetch,还可监听 abort 事件,手动控制任意异步逻辑:
- 用
signal.addEventListener('abort', handler)监听取消 - 在 handler 中清理资源(如清除
setTimeout、关闭 WebSocket、中断 Canvas 动画等) - 也可用
signal.throwIfAborted()在任意位置抛出AbortError
示例(取消延时任务):
function delayedTask(ms, controller) {
const timeoutId = setTimeout(() => {
console.log('任务执行');
}, ms);
controller.signal.addEventListener('abort', () => {
clearTimeout(timeoutId);
console.log('任务已取消');
});
}
// 使用
const controller = new AbortController();
delayedTask(3000, controller);
// 1 秒后取消
setTimeout(() => controller.abort(), 1000);
注意事项与最佳实践
实际使用中容易忽略几个关键细节:
-
不要复用同一个 AbortController:每个请求/任务应有独立实例,否则多个地方调用
abort()会互相干扰 -
捕获并区分 AbortError:避免把取消当成真实错误上报;建议统一判断
err.name === 'AbortError' - 及时释放引用:尤其在闭包或长生命周期对象中,避免 controller 持有不必要的 DOM 或数据引用导致内存泄漏
- 服务端配合更佳:虽然前端取消了请求,但服务端可能仍在执行;如有必要,可在 URL 中加唯一 traceId,服务端收到重复 ID 时主动跳过处理

















