在现代前端开发中,fetch 已经成为发送 HTTP 请求的标准方式。但在实际开发中,我们常常会遇到这样的问题:当用户离开页面或组件卸载时,仍然有请求在进行,这可能导致内存泄漏或无意义的数据处理。为了解决这个问题,Fetch API 提供了 AbortController 来支持取消请求。
为什么需要取消请求
- 组件卸载:在 React、Vue 等框架中,组件卸载后仍然请求数据会导致状态更新报错。
- 多次请求冲突:用户频繁触发搜索或筛选,旧请求返回的数据可能覆盖新请求的数据。
- 节省资源:不必要的请求会浪费带宽和服务器资源。
AbortController 基础用法
AbortController 是浏览器提供的原生 API,用于控制和取消异步操作。
示例如下:
const controller = new AbortController();
const signal = controller.signal;
fetch('https://api.example.com/data', { signal })
.then(response => response.json())
.then(data => console.log(data))
.catch(err => {
if (err.name === 'AbortError') {
console.log('请求被取消');
} else {
console.error('请求出错:', err);
}
});
// 在需要取消请求的时候调用
controller.abort();
- new AbortController():创建一个控制器。
- controller.signal:传给 fetch 的 signal 属性。
- controller.abort():主动取消请求。
- 异常捕获中,通过
err.name === 'AbortError'判断请求是否被取消。
React 中取消请求的场景
在 React 中,最常见的场景是组件卸载时取消请求:
import { useEffect } from 'react';
function MyComponent() {
useEffect(() => {
const controller = new AbortController();
const signal = controller.signal;
fetch('https://api.example.com/data', { signal })
.then(res => res.json())
.then(data => console.log(data))
.catch(err => {
if (err.name === 'AbortError') {
console.log('请求被取消');
}
});
// 组件卸载时取消请求
return () => controller.abort();
}, []);
return <div>MyComponent</div>;
}
这样就保证了组件卸载时,不会再尝试处理 fetch 的返回结果。
多个请求的取消策略
如果有多个请求,需要同时取消,可以使用一个 控制器数组 或 统一管理的 AbortController:
const controllers = [];
function fetchData(url) {
const controller = new AbortController();
controllers.push(controller);
return fetch(url, { signal: controller.signal });
}
// 取消所有请求
function cancelAllRequests() {
controllers.forEach(c => c.abort());
controllers.length = 0;
}
要注意的地方
- 兼容性:AbortController 在现代浏览器中均支持,但 IE 不支持。
- 重复调用:调用 abort() 后,fetch 会立即 reject,并触发 AbortError 错误类型。