如何在 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 requestcontroller.abort();
终止 Web 请求对于以下情况很有用:
- 根据用户操作取消请求。
- 在有多个并发请求的情况下,优先处理最新的请求。
- 取消不再需要的请求,例如,在用户已从页面导航离开之后。
AbortController
s
AbortController
允许优雅地取消进行中的异步操作,例如 fetch 请求。 它提供了一种机制,向底层网络层发出信号,表明不再需要该请求,从而防止不必要的资源消耗并改善用户体验。
使用 AbortController
s
使用 AbortController
涉及以下步骤:
- 创建
AbortController
实例:初始化一个AbortController
实例,它会创建一个可用于中止请求的信号。 - 将信号传递给请求:将信号传递给请求,通常通过请求选项中的
signal
属性。 - 中止请求:在
AbortController
实例上调用abort()
方法以取消正在进行的请求。
以下是如何将 AbortController
与 fetch()
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 requestcontroller.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 controllerfunction 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 onesetTimeout(() => {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()
不会向服务器发送任何通知或信号。服务器不知道取消操作,并将继续处理请求,直到它完成或超时。