测验

如何在 JavaScript 中使用 `AbortController` 终止 Web 请求?

主题
JavaScript网络
在GitHub上编辑

TL;DR

AbortController 用于取消进行中的异步操作,例如 fetch 请求。

const controller = new AbortController();
const signal = controller.signal;
fetch('https://jsonplaceholder.typicode.com/todos/1', { signal })
.then((response) => {
// Handle response
})
.catch((error) => {
if (error.name === 'AbortError') {
console.log('Request aborted');
} else {
console.error('Error:', error);
}
});
// Call abort() to abort the request
controller.abort();

终止 Web 请求对于以下情况很有用:

  • 根据用户操作取消请求。
  • 在有多个并发请求的情况下,优先处理最新的请求。
  • 取消不再需要的请求,例如,在用户已从页面导航离开之后。

AbortControllers

AbortController 允许优雅地取消进行中的异步操作,例如 fetch 请求。 它提供了一种机制,向底层网络层发出信号,表明不再需要该请求,从而防止不必要的资源消耗并改善用户体验。

使用 AbortControllers

使用 AbortController 涉及以下步骤:

  1. 创建 AbortController 实例:初始化一个 AbortController 实例,它会创建一个可用于中止请求的信号。
  2. 将信号传递给请求:将信号传递给请求,通常通过请求选项中的 signal 属性。
  3. 中止请求:在 AbortController 实例上调用 abort() 方法以取消正在进行的请求。

以下是如何将 AbortControllerfetch() API 结合使用的示例:

const controller = new AbortController();
const signal = controller.signal;
fetch('https://jsonplaceholder.typicode.com/todos/1', { signal })
.then((response) => {
// Handle response
})
.catch((error) => {
if (error.name === 'AbortError') {
console.log('Request aborted');
} else {
console.error('Error:', error);
}
});
// Call abort() to abort the request
controller.abort();

用例

在用户操作时取消 fetch() 请求

取消由于用户交互(例如,用户取消上传一个大文件)而导致耗时过长或不再相关的请求。

// HTML: <button id='cancel-button'>Cancel upload</button>
const btn = document.createElement('button');
btn.id = 'cancel-button';
btn.innerHTML = 'Cancel upload';
document.body.appendChild(btn);
const controller = new AbortController();
const signal = controller.signal;
fetch('https://jsonplaceholder.typicode.com/todos/1', { signal })
.then((response) => {
// Handle successful response
})
.catch((error) => {
if (error.name === 'AbortError') {
console.log('Request canceled');
} else {
console.error('Network or other error:', error);
}
});
document.getElementById('cancel-button').addEventListener('click', () => {
controller.abort();
});
document.getElementById('cancel-button').click(); // Simulate clicking the cancel button

当您单击“取消上传”按钮时,正在进行的请求将被中止。

在竞争条件下优先处理最新请求

在为相同数据启动多个请求的情况下,使用 AbortController 优先处理最新请求并中止较早的请求。

let latestController = null; // Keeps track of the latest controller
function fetchData(url) {
if (latestController) {
latestController.abort(); // Abort any previous request
}
const controller = new AbortController();
latestController = controller;
const signal = controller.signal;
fetch(url, { signal })
.then((response) => response.json())
.then((data) => console.log('Fetched data:', data))
.catch((error) => {
if (error.name === 'AbortError') {
console.log('Request canceled');
} else {
console.error('Network or other error:', error);
}
});
}
fetchData('https://jsonplaceholder.typicode.com/posts/1');
// Simulate race conditions with new requests that quickly cancel the previous one
setTimeout(() => {
fetchData('https://jsonplaceholder.typicode.com/posts/2');
}, 5);
setTimeout(() => {
fetchData('https://jsonplaceholder.typicode.com/posts/3');
}, 5);
// Only the last request should (posts/3) will be allowed to complete

在本例中,当多次调用 fetchData() 函数触发多个 fetch 请求时,AbortController 将取消所有之前的请求,除了最新的请求。这在诸如类型提示搜索或无限滚动等场景中很常见,在这些场景中,会频繁触发新的请求。

取消不再需要的请求

在用户已从页面导航出去的情况下,中止请求可以防止不必要的操作(例如,成功回调处理),并通过降低内存泄漏的可能性来释放资源。

笔记

  • AbortController 并非 fetch() 专有,它也可以用于中止其他异步任务。
  • 一个单独的 AbortContoller 实例可以被重用或用于多个异步任务,并一次性取消所有任务。
  • AbortController 上调用 abort() 不会向服务器发送任何通知或信号。服务器不知道取消操作,并将继续处理请求,直到它完成或超时。

延伸阅读

在GitHub上编辑