AbortController 与异步取消
解释 AbortController 和 AbortSignal 如何传播取消意图,以及 fetch、流读取和 React effect 应如何共同管理任务生命周期。
#type / concept
#status / evergreen
#tech / dev / frontend
#resource / javascript
#platform / browser
[!info] related notes
- 流读取:Web Streams 与增量文本解码
- React 副作用:React 副作用与外部系统
- 查询取消:TanStack Query 与 AbortController
AbortController 与异步取消
一句话定义
AbortController 创建和触发取消,AbortSignal 把取消状态传给支持它的异步 API;取消是协作协议,不是强制杀死任意 JavaScript 函数。
const controller = new AbortController();
try {
const response = await fetch(url, { signal: controller.signal });
// 继续读取 response.body
} catch (error) {
if (error instanceof DOMException && error.name === 'AbortError') {
return;
}
throw error;
}
所有权
启动任务的一方通常负责:
- 持有 controller
- 在用户取消、组件卸载或新任务替代旧任务时调用
abort() - 区分预期取消和真实失败
下游函数接收 AbortSignal,不应随意替调用方决定何时取消整个任务。
React effect
useEffect(() => {
const controller = new AbortController();
void loadData(controller.signal);
return () => controller.abort();
}, [key]);
清理函数使旧 effect 的任务在依赖变化或组件卸载时停止。它同时减少无意义网络工作和旧响应覆盖新状态的竞态。
取消流读取
把 signal 交给 fetch 通常会使 body 读取也失败退出。还应确保循环捕获取消异常、停止分发事件,并在需要时释放 reader。
常见误解
abort()不会回滚已经发生的服务端副作用。- Promise 本身没有通用强制取消;必须由具体 API 协作。
- 把取消当普通错误弹给用户会制造噪声。
- 只用
isMounted忽略结果不能停止网络和服务器工作。