你真的会用 Fetch 吗?深入 AbortController 实现请求取消
4 min
1. Fetch API:现代 Web 请求的基石
Fetch API 已经取代了老旧的 XMLHttpRequest,成为浏览器中发起 HTTP 请求的标准方式。它基于 Promise,提供了更简洁、更强大的请求能力。
然而,Fetch API 默认并没有提供一个直接取消请求的机制。在许多场景下,请求取消是一个非常重要的功能:
- 性能优化: 用户快速切换页面或输入搜索词时,取消旧的、不再需要的请求可以节省带宽和服务器资源。
- 避免竞态条件: 在“搜索即时输入”的场景中,如果旧的请求比新的请求返回得慢,可能会导致 UI 显示过时的数据。
- 防止内存泄漏: 在组件生命周期中发起的请求,如果组件在请求完成前被卸载,尝试更新一个不存在的组件可能会导致错误或内存泄漏。
2. AbortController:通用的取消信号
AbortController 是一个通用的 Web API,它提供了一种机制来中止一个或多个 Web 请求。它独立于 Fetch API,但可以与 Fetch 完美配合。
AbortController 的核心思想是:
- 创建一个
AbortController实例。 - 从这个实例中获取一个
AbortSignal对象。 - 将
AbortSignal传递给可中止的 Web API(如fetch)。 - 当你需要取消时,调用
AbortController实例的abort()方法。
3. AbortController 与 Fetch 的结合
让我们通过一个例子来看看如何使用 AbortController 来取消 Fetch 请求。
const controller = new AbortController();
const signal = controller.signal; // 获取信号对象
async function fetchDataWithCancellation(url) {
try {
console.log('Fetching data...');
const response = await fetch(url, { signal }); // 将信号传递给 fetch
const data = await response.json();
console.log('Data received:', data);
return data;
} catch (error) {
if (error.name === 'AbortError') {
console.log('Fetch request was aborted.');
} else {
console.error('Fetch error:', error);
}
}
}
// 示例用法
const promise = fetchDataWithCancellation('https://jsonplaceholder.typicode.com/posts/1');
// 假设在 500 毫秒后,我们决定取消这个请求
setTimeout(() => {
controller.abort(); // 调用 abort() 方法取消请求
console.log('Request aborted by timeout.');
}, 500);当 controller.abort() 被调用时,fetch 请求会立即中止,并抛出一个 AbortError。你需要在 catch 块中捕获这个错误,并检查 error.name === 'AbortError' 来区分是取消操作还是其他网络错误。
4. 实际应用场景
a. 搜索即时输入 (Search-as-you-type)
当用户在搜索框中快速输入时,每次输入都可能触发一个新的请求。我们可以取消前一个未完成的请求,只保留最新的请求。
let currentController = null;
document.getElementById('searchInput').addEventListener('input', (event) => {
if (currentController) {
currentController.abort(); // 取消上一个请求
}
currentController = new AbortController();
const signal = currentController.signal;
const query = event.target.value;
if (query.length > 2) {
fetchDataWithCancellation(`/api/search?q=${query}`, signal);
}
});b. 组件卸载时取消请求 (Component Unmount)
在 React 或 Vue 等框架中,当组件卸载时,取消其内部发起的未完成请求可以有效避免内存泄漏和不必要的 UI 更新。
// React 示例
useEffect(() => {
const controller = new AbortController();
fetchDataWithCancellation('/api/data', controller.signal);
return () => {
controller.abort(); // 组件卸载时取消请求
};
}, []);结论
AbortController 是现代 Web 开发中一个不可或缺的工具。它为 Fetch API 和其他异步操作提供了原生的取消机制,帮助开发者构建更健壮、更高效、用户体验更好的应用。掌握 AbortController 的使用,是成为一名优秀前端开发者的必备技能之一。