通过递归调用 promise 构造函数并配合 settimeout 实现延迟重试。核心做法是封装一个函数,在 catch 块中判断是否达到最大重试次数,若未达标则使用 settimeout 延迟指定毫秒后再次执行该 promise 逻辑,直到成功或失败。

如何封装通用的重试逻辑
定义一个接受异步函数、重试次数和延迟时间的工具函数。利用闭包保存当前重试状态,每次失败时返回一个新的 Promise 并在其中设置定时器触发下一次调用。
function retryAsync(fn, maxRetries = 3, delayMs = 1000) {
let attempts = 0;
return new Promise((resolve, reject) => {
function attempt() {
attempts++;
fn()
.then(resolve)
.catch(err => {
if (attempts <= maxRetries) {
console.log(`Retry ${attempts}/${maxRetries}`);
setTimeout(attempt, delayMs);
} else {
reject(err);
}
});
}
attempt();
});
}预期结果:当 fn 抛出错误且重试次数未耗尽时,控制台打印重试信息并继续执行;耗尽后抛出最终错误。

立即学习“Java免费学习笔记(深入)”;
如何处理网络请求中的指数退避
将固定延迟改为基于重试次数的指数增长延迟。修改 setTimeout 的等待时间为 delayMs * Math.pow(2, attempts - 1),避免频繁请求导致服务器压力过大。
function exponentialRetryAsync(fn, maxRetries = 5, baseDelayMs = 1000) {
let attempts = 0;
return new Promise((resolve, reject) => {
function attempt() {
attempts++;
fn()
.then(resolve)
.catch(err => {
if (attempts <= maxRetries) {
const waitTime = baseDelayMs * Math.pow(2, attempts - 1);
console.log(`Exponential wait: ${waitTime}ms`);
setTimeout(attempt, waitTime);
} else {
reject(err);
}
});
}
attempt();
});
}预期结果:第一次失败等待 1s,第二次 2s,第三次 4s,依此类推,直到成功或达到最大重试次数。

基于程序中某个输入、条件或结果的具体问题
当异步函数本身返回的是非 Promise 对象(如普通值)时,上述封装依然有效,因为 Promise 构造函数会自动包装非 Promise 值。但若异步函数内部使用了 try-catch 吞掉了异常,则外层重试逻辑无法捕获错误,导致无限循环或静默失败。因此需确保被重试的函数在失败时正确抛出 Error 对象。


















