在 TypeScript 中使用
AbortController
来取消异步请求,尤其是像
fetch
这样的请求,可以提供一种优雅的方式来中止长时间运行的操作。下面是一个详细的步骤说明,展示如何在 TypeScript 中使用
AbortController
取消
fetch
请求。
步骤 1:创建
AbortController
实例
首先,你需要创建一个
AbortController
实例,并从中获取
signal
对象。这个
signal
对象将在请求中使用,以便在需要时取消请求。
const controller =newAbortController();const signal = controller.signal;
步骤 2:发送带有
signal
的请求
当使用
fetch
发送请求时,传递
signal
作为选项的一部分。如果请求被取消,
fetch
将会抛出一个带有
name
属性为
"AbortError"
的错误。
fetch('/api/data',{ signal }).then(response =>{if(!response.ok){thrownewError(`HTTP error! Status: ${response.status}`);}return response.json();}).then(data =>{console.log(data);}).catch(error =>{if(error.name ==='AbortError'){console.log('Fetch operation was aborted');}else{console.error('Fetch operation failed:', error);}});
步骤 3:取消请求
在某个时刻,如果你决定要取消请求,只需调用
controller.abort()
方法即可。
setTimeout(()=>{
controller.abort();},3000);// 取消请求将在3秒后发生
示例:完整的代码示例
下面是一个完整的示例,展示了如何使用
AbortController
来取消一个
fetch
请求:
// 示例:使用 AbortController 取消 fetch 请求const controller =newAbortController();const signal = controller.signal;// 在3秒后取消请求setTimeout(()=>{
controller.abort();},3000);// 发送带有 signal 的请求fetch('/api/data',{ signal }).then(response =>{if(!response.ok){thrownewError(`HTTP error! Status: ${response.status}`);}return response.json();}).then(data =>{console.log('Received data:', data);}).catch(error =>{if(error.name ==='AbortError'){console.log('Fetch operation was aborted');}else{console.error('Fetch operation failed:', error);}});
在使用
AbortController
取消请求后,如果需要重新尝试发送请求,可以采用几种不同的策略。下面将介绍如何在 TypeScript 中实现重新尝试的逻辑。
1. 手动重新尝试
最简单的方法是在请求被取消后手动重新触发请求。这种方法适用于你知道何时应该重新尝试的情况,比如在某些用户操作之后。
const controller =newAbortController();const signal = controller.signal;// 发送带有 signal 的请求fetch('/api/data',{ signal }).then(response =>{if(!response.ok){thrownewError(`HTTP error! Status: ${response.status}`);}return response.json();}).then(data =>{console.log('Received data:', data);}).catch(error =>{if(error.name ==='AbortError'){console.log('Fetch operation was aborted');// 手动重新尝试setTimeout(()=>{
controller =newAbortController();
signal = controller.signal;fetch('/api/data',{ signal }).then(response =>{if(!response.ok){thrownewError(`HTTP error! Status: ${response.status}`);}return response.json();}).then(data =>{console.log('Retried and received data:', data);}).catch(error =>{console.error('Retry failed:', error);});},5000);// 5秒后重新尝试}else{console.error('Fetch operation failed:', error);}});
2. 使用重试库
另一种方法是使用重试库,例如
p-retry
或者
retry
,它们可以自动处理重试逻辑,并提供灵活的配置选项。
示例:使用 p-retry
首先安装
p-retry
:
npminstall p-retry
然后在代码中使用它:
import retry from'p-retry';asyncfunctionfetchData(signal: AbortSignal):Promise<any>{returnfetch('/api/data',{ signal }).then(res => res.json());}retry(()=>fetchData(signal),{ retries:3, factor:2, minTimeout:1000, maxTimeout:3000}).then(data =>{console.log('Received data:', data);}).catch(error =>{console.error('Fetch operation failed:', error);});
3. 自定义重试逻辑
你也可以自己编写重试逻辑,根据需要调整重试次数、间隔时间等参数。
constMAX_RETRIES=3;constRETRY_INTERVAL=1000;// 间隔时间(毫秒)asyncfunctionfetchData(signal: AbortSignal):Promise<any>{returnfetch('/api/data',{ signal }).then(res => res.json());}asyncfunctionretryFetch(signal: AbortSignal, retriesLeft:number=MAX_RETRIES):Promise<any>{try{returnawaitfetchData(signal);}catch(error){if(error.name ==='AbortError'&& retriesLeft >0){console.log(`Fetch operation was aborted, retrying... (${retriesLeft} attempts left)`);awaitnewPromise(resolve =>setTimeout(resolve,RETRY_INTERVAL));returnretryFetch(signal, retriesLeft -1);}else{throw error;}}}retryFetch(signal).then(data =>{console.log('Received data:', data);}).catch(error =>{console.error('Fetch operation failed:', error);});
4. 使用
AbortController
的组合策略
你还可以结合使用
AbortController
和重试逻辑,以实现更复杂的场景。例如,在某些条件下取消请求,并在满足一定条件时重新尝试。
const controller =newAbortController();const signal = controller.signal;// 在满足某些条件下取消请求setTimeout(()=>{if(/* 某些条件 */){
controller.abort();}},3000);// 发送带有 signal 的请求fetch('/api/data',{ signal }).then(response =>{if(!response.ok){thrownewError(`HTTP error! Status: ${response.status}`);}return response.json();}).then(data =>{console.log('Received data:', data);}).catch(error =>{if(error.name ==='AbortError'){console.log('Fetch operation was aborted');// 根据条件重新尝试if(/* 满足重新尝试的条件 */){const newController =newAbortController();const newSignal = newController.signal;fetch('/api/data',{ signal: newSignal }).then(response =>{if(!response.ok){thrownewError(`HTTP error! Status: ${response.status}`);}return response.json();}).then(data =>{console.log('Retried and received data:', data);}).catch(error =>{console.error('Retry failed:', error);});}}else{console.error('Fetch operation failed:', error);}});
注意事项
- 兼容性:请确保你的浏览器或 Node.js 版本支持
AbortController
。对于不支持的环境,你可能需要考虑使用 polyfills。 - 信号传播:如果你在请求中使用了中间件(例如代理服务器),请注意
AbortController
的信号可能不会被正确传播。在这种情况下,你可能需要手动处理信号的传播。 - 资源释放:取消请求后,确保适当释放资源。例如,如果请求涉及文件上传,取消请求后应确保删除临时文件。
使用 AbortController 的好处
- 更好的用户体验:用户可以在长时间的请求未完成前取消请求,减少无响应的情况。
- 资源管理:可以避免因长时间未完成的请求而导致的资源浪费。
- 灵活性:为异步操作提供了一种灵活的控制机制。
通过这种方式,你可以有效地在 TypeScript 中使用
AbortController
来管理异步请求的生命周期。
版权归原作者 奔跑草- 所有, 如有侵权,请联系我们删除。