JavaScript 请求取消
在构建现代 Web 应用程序时,管理网络请求是一项重要技能。有时候,我们需要取消已经发出但尚未完成的网络请求,比如当用户导航到其他页面或撤销了某个操作时。请求取消可以节省带宽、减少不必要的数据处理,并提高应用的响应速度。
为什么需要取消请求?
在以下情况中,取消请求特别有用:
- 用户快速切换页面或视图
- 搜索框实时搜索,用户输入新内容
- 用户取消了文件上传
- 请求超时,需要中止
- 防止竞态条件(后发出的请求结果先返回)
XMLHttpRequest 取消请求
对于传统的 XMLHttpRequest
,取消请求是通过调用 abort()
方法实现的。
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.example.com/data');
xhr.send();
// 取消请求
xhr.abort();
备注
调用 abort()
后,XHR 对象会触发 abort
事件,可以通过 onabort
处理程序或事件监听器来捕获。
Fetch API 请求取消
现代的 Fetch API 使用 AbortController
接口来实现请求取消功能。这是一个更优雅的解决方案。
基本用法
// 创建 AbortController 实例
const controller = new AbortController();
const signal = controller.signal;
// 发起请求,并传入 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('Fetch 请求被取消了');
} else {
console.error('发生其他错误:', err);
}
});
// 某个时刻取消请求
controller.abort();
当调用 controller.abort()
时,与 signal 关联的 fetch 请求会立即被取消,并且 promise 会以 AbortError
错误被拒绝。
设置超时自动取消
一个常见的需求是给请求设置超时时间。使用 AbortController
,我们可以轻松实现这一功能:
function fetchWithTimeout(url, options = {}, timeout = 5000) {
const controller = new AbortController();
const { signal } = controller;
// 创建一个超时定时器
const timeoutId = setTimeout(() => controller.abort(), timeout);
return fetch(url, { ...options, signal })
.then(response => {
clearTimeout(timeoutId);
return response;
})
.catch(err => {
clearTimeout(timeoutId);
if (err.name === 'AbortError') {
throw new Error('请求超时');
}
throw err;
});
}
// 使用示例
fetchWithTimeout('https://api.example.com/data', {}, 3000)
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error.message));
Axios 请求取消
如果你使用 Axios 库来处理 HTTP 请求,它也提供了取消请求的功能。