Promise本身不内置重试逻辑,需封装函数通过捕获reject、延迟后递归调用实现;支持配置重试次数、延迟时间、错误类型判断,并应在最终失败时抛出错误以便上层处理。

Promise 本身不内置重试逻辑,但可以通过封装函数,在捕获错误后递归或循环调用自身来实现自动重试。
核心思路:捕获 reject,延迟后重新执行
关键在于把原始请求包装成一个可重复调用的函数,并在 catch 中判断是否达到重试次数上限。没到上限就等待一段时间再发起下一次 Promise。
- 每次失败后用 setTimeout 或 Promise.delay 暂停,避免瞬间重试压垮服务
- 重试次数、延迟时间、是否对特定错误码重试,都应支持配置
- 最终失败时,仍应 throw 错误,便于上层统一处理
基础重试函数示例
下面是一个通用的 retry 包装器:
function retry(fn, options = {}) {
const { maxRetries = 3, delay = 1000, shouldRetry = () => true } = options;
<p>return function(...args) {
return fn(...args).catch(err => {
if (maxRetries <= 0 || !shouldRetry(err)) {
throw err;
}
return new Promise(resolve => setTimeout(() => resolve(), delay))
.then(() => retry(fn, { ...options, maxRetries: maxRetries - 1 })(...args));
});
};
}使用方式:
立即学习“Java免费学习笔记(深入)”;
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
const fetchWithRetry = retry(() => fetch('/api/data'), {
maxRetries: 2,
delay: 2000,
shouldRetry: err => err instanceof TypeError || err.status === 503
});
<p>fetchWithRetry().then(res => res.json()).catch(console.error);用 async/await 写更直观的重试逻辑
避免嵌套 Promise.then,改用 await + for 循环更易读:
async function retryAsync(fn, options = {}) {
const { maxRetries = 3, delay = 1000, shouldRetry = () => true } = options;
<p>for (let i = 0; i <= maxRetries; i++) {
try {
return await fn();
} catch (err) {
if (i === maxRetries || !shouldRetry(err)) throw err;
await new Promise(r => setTimeout(r, delay));
}
}
}调用时直接 await:
try {
const data = await retryAsync(() => fetch('/api/user').then(r => r.json()), {
maxRetries: 2,
delay: 1500
});
} catch (e) {
console.error('请求最终失败', e);
}进阶:指数退避 + 取消机制
生产环境建议加入指数退避(delay 随重试次数增长)和 abortSignal 支持:
- 延迟时间可设为 delay * 2^retryCount,缓解服务压力
- 传入 AbortController.signal,让外部能主动中止所有重试尝试
- 对网络中断、超时等错误分类处理,比如 401 不重试,5xx 才重试
不复杂但容易忽略细节,比如没清空定时器、没区分错误类型、没传递 signal,都会影响稳定性。

















