使用 abortcontroller 实例的 signal 属性传递给 fetch 即可实现请求预取消。调用 controller.abort() 会立即中断当前正在进行的网络请求,并抛出一个带有 name: "aborterror" 属性的 domexception。开发者只需在 try...catch 块中捕获该异常并进行处理,就能确保资源被正确释放且不会更新 ui。

如何创建控制器并绑定信号
通过实例化 new AbortController() 获取控制器对象,并将其 signal 属性作为配置项传入 fetch 的第二个参数中。这样建立连接后,控制器的状态将直接决定请求的生命周期。
const controller = new AbortController();
const signal = controller.signal;
fetch('https://api.example.com/data', {
signal: signal
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => {
if (error.name === 'AbortError') {
console.log('Fetch aborted');
} else {
console.error('Fetch failed:', error);
}
});上述代码展示了标准的绑定方式。当 fetch 发起请求时,它会监听 signal 的状态。如果此时调用 controller.abort(),浏览器会中止网络连接,Promise 链将直接进入 catch 分支。
如何在超时或交互时触发取消
在实际业务中,通常需要在特定条件下(如用户离开页面、输入新关键词或请求超时)主动触发取消。可以通过 setTimeout 模拟超时,或者绑定事件监听器来实现自动化管理。
立即学习“Java免费学习笔记(深入)”;
const controller = new AbortController();
const signal = controller.signal;
// 设置5秒超时自动取消
const timeoutId = setTimeout(() => {
controller.abort();
}, 5000);
fetch('https://api.example.com/slow-data', {
signal: signal
})
.then(response => {
clearTimeout(timeoutId); // 请求成功则清除定时器
return response.json();
})
.then(data => console.log(data))
.catch(error => {
if (error.name === 'AbortError') {
console.log('Request timed out or aborted');
} else {
console.error('Error:', error);
}
});这段代码演示了超时控制的逻辑。如果在 5 秒内请求未完成,timeoutId 回调将执行 abort(),从而中断请求。若请求在超时前完成,则清除定时器以避免内存泄漏。这种模式常用于防止慢速请求阻塞界面响应。
取消后重新发起请求如何处理旧数据
当用户快速连续触发请求(如搜索框输入)时,之前的请求可能尚未完成。如果直接覆盖状态,旧请求的响应可能会晚于新请求到达,导致显示错误的数据。需要在每次发起新请求前取消上一个未完成的请求。
let currentController = null;
function search(query) {
// 取消上一次未完成的请求
if (currentController) {
currentController.abort();
}
// 创建新的控制器
currentController = new AbortController();
const signal = currentController.signal;
fetch(`/api/search?q=${query}`, { signal })
.then(res => res.json())
.then(data => {
// 只有当当前信号未被中止时才更新UI
if (!signal.aborted) {
renderResults(data);
}
})
.catch(err => {
if (!err.name === 'AbortError') {
console.error(err);
}
});
}该示例展示了防抖场景下的最佳实践。在每次调用 search 时,先检查是否存在旧的 currentController,若存在则调用 abort() 取消旧请求。随后创建新的控制器并绑定信号。在 then 回调中,通过检查 signal.aborted 属性来确保只渲染最新请求的结果,从而避免竞态条件导致的 UI 错乱。


















