如何用Promise(await)处理多次连续失败的异步请求
实现带自动重试的异步请求函数
嘿,我明白你想要的是一个简洁清晰、能自动重试失败请求的async函数——这其实是异步编程里很常见的需求,咱们可以把重试逻辑和业务请求拆分开来写,既清晰又好维护!
先写一个通用的重试工具函数
首先咱们搞一个通用的retry函数,它负责处理重试的循环逻辑,把具体的异步任务(比如你的HTTP请求)当成参数传进去就行:
async function retry(asyncTask, maxAttempts) { let attemptCount = 0; while (attemptCount < maxAttempts) { try { // 执行异步任务,成功就直接返回结果 return await asyncTask(); } catch (error) { attemptCount++; // 如果是最后一次尝试失败,直接抛出错误给上层处理 if (attemptCount === maxAttempts) { throw new Error(`试过${maxAttempts}次都失败了:${error.message}`); } // 可选:加个指数退避延迟,避免频繁请求压垮服务器 await new Promise(resolve => setTimeout(resolve, 1000 * attemptCount)); console.log(`第${attemptCount}次失败,马上进行第${attemptCount + 1}次重试...`); } } }
结合你的HTTP请求使用
接下来把你的HTTP请求逻辑封装成一个单独的async函数,然后丢给retry函数就行,这样业务逻辑和重试逻辑完全分离,看着清爽:
// 模拟你的HTTP请求,这里用fetch举例子,你换成自己的请求库也一样 async function makeHttpRequest() { // 这里放你HTTP请求前的操作 console.log("准备发起请求啦..."); const response = await fetch("https://your-api-url.com/your-endpoint"); if (!response.ok) { // 请求返回错误状态码时主动抛出错误,触发重试 throw new Error(`请求失败,状态码:${response.status}`); } return await response.json(); } // 你的主函数 async function func() { try { // 最多重试3次,你可以改成任意数字n const result = await retry(makeHttpRequest, 3); console.log("请求成功!拿到的数据:", result); // 这里写请求成功后的后续逻辑 } catch (error) { console.error("彻底失败了:", error.message); // 处理最终失败的情况 } } // 执行主函数 func();
为啥这么写?给你拆解下逻辑
- 解耦设计:把重试逻辑抽成通用函数,以后任何需要重试的异步任务都能直接用,不用重复写代码。
- 清晰的流程:用while循环控制重试次数,每一步的逻辑都一目了然,比嵌套Promise链好维护太多。
- 错误控制:只有当所有重试都用完了才会抛出最终错误,上层函数可以统一处理失败情况。
- 友好的重试策略:加了指数退避延迟(每次重试等的时间翻倍),这是后端请求的最佳实践,能减少对服务器的冲击,你也可以根据需求调整延迟时间。
可选扩展:只重试特定错误
如果你的需求是只针对某些错误(比如超时、网络错误)重试,而不是所有错误都重试,可以给retry函数加个参数:
async function retry(asyncTask, maxAttempts, retryableErrorTypes = []) { let attemptCount = 0; while (attemptCount < maxAttempts) { try { return await asyncTask(); } catch (error) { attemptCount++; // 判断当前错误是否属于需要重试的类型 const shouldRetry = retryableErrorTypes.length === 0 ? true : retryableErrorTypes.some(errType => error instanceof errType); // 如果是最后一次尝试,或者错误不可重试,就抛出最终错误 if (attemptCount === maxAttempts || !shouldRetry) { throw new Error(`试过${attemptCount}次都失败了:${error.message}`); } await new Promise(resolve => setTimeout(resolve, 1000 * attemptCount)); console.log(`第${attemptCount}次失败(属于可重试错误),马上重试...`); } } } // 用法示例:只针对超时错误重试 // 假设你有一个自定义的TimeoutError类 retry(makeHttpRequest, 3, [TimeoutError]);
这样写出来的代码既简洁又灵活,完全符合你的需求!
内容的提问来源于stack exchange,提问作者Michele Tuloski Furci
相关产品推荐
相关产品推荐

