主题
AbortController
AbortController 用于取消异步操作,最常见的场景是取消 fetch 请求,也可以和其他支持 AbortSignal 的 Web API 配合使用。
基本概念
它主要包含两部分:
AbortController:负责发出取消信号AbortSignal:传给目标 API 的信号对象
js
const controller = new AbortController()
const { signal } = controller最常见场景:取消 fetch
js
const controller = new AbortController()
fetch('/api/users', {
signal: controller.signal,
})
.then((response) => response.json())
.then((data) => {
console.log(data)
})
.catch((error) => {
if (error.name === 'AbortError') {
console.log('请求已取消')
return
}
console.error(error)
})
controller.abort()调用 abort() 后,请求通常会以 AbortError 结束。
为什么要主动取消请求
很多时候不是“请求发错了”,而是“这个请求已经没有继续存在的价值”。
典型情况包括:
- 页面已经切走
- 新请求已经替代旧请求
- 到了超时时间
典型场景
组件卸载时取消请求
避免页面切换后无意义的请求继续执行。
js
const controller = new AbortController()
fetch('/api/detail', { signal: controller.signal })
window.addEventListener('beforeunload', () => {
controller.abort()
})搜索联想只保留最后一次请求
js
let controller
async function search(keyword) {
controller?.abort()
controller = new AbortController()
const response = await fetch(`/api/search?q=${encodeURIComponent(keyword)}`, {
signal: controller.signal,
})
return response.json()
}这类场景里,取消旧请求通常比“等旧请求回来再丢弃结果”更直接。
超时控制
fetch 本身没有原生 timeout 配置,所以很常见的一种做法就是配合 AbortController 自己封装:
js
async function fetchWithTimeout(url, timeout = 5000) {
const controller = new AbortController()
const timer = setTimeout(() => controller.abort(), timeout)
try {
return await fetch(url, {
signal: controller.signal,
})
} finally {
clearTimeout(timer)
}
}这也是它在项目里最常见的价值之一。
和事件监听配合
部分浏览器 API 支持把 signal 传给 addEventListener,取消时可自动移除监听器。
js
const controller = new AbortController()
window.addEventListener(
'resize',
() => {
console.log('resize')
},
{ signal: controller.signal },
)
controller.abort()这表示同一个取消信号不只可以控制请求,也可以控制部分事件监听生命周期。
使用时要注意什么
AbortError 不是普通业务失败
js
try {
await fetch('/api/users', { signal: controller.signal })
} catch (error) {
if (error.name === 'AbortError') {
return
}
throw error
}如果不单独区分,日志里很容易把“主动取消”误判成“接口报错”。
取消不等于回滚服务端操作
abort() 更多是终止浏览器侧这条异步流程,并不一定意味着服务端已经完全停止处理。
使用建议
- 请求存在竞态时,优先考虑取消旧请求,而不是只在结果返回后再判断是否丢弃。
- 处理异常时,单独识别
AbortError,不要把它当成真正的接口失败。 - 如果只是做超时控制,也可以基于
AbortController自己封装超时取消。
