如何实现Promise重试机制?

在网络请求或其它不可靠的异步操作中,失败是常事。一个健壮的系统需要具备重试能力。为Promise实现重试机制,意味着在操作失败后自动尝试重新执行,直到成功或达到最大重试次数。

实现一个基础的重试函数

核心思路是循环执行一个创建Promise的函数。如果成功,则返回结果;如果失败,则等待一段时间后再次尝试,直到重试次数用尽。

function retry(fn, maxAttempts, delay) {
  return new Promise((resolve, reject) => {
    const attempt = (count) => {
      fn().then(resolve).catch(error => {
        if (count >= maxAttempts) {
          reject(error);
        } else {
          setTimeout(() => attempt(count + 1), delay);
        }
      });
    };
    attempt(1);
  });
}

// 使用
const unstableTask = () => fetch('/api/data');
retry(unstableTask, 3, 1000)
  .then(data => console.log('成功'))
  .catch(err => console.log('重试多次后失败', err));

这个实现会在每次失败后等待固定的延迟时间(1秒)再重试。它简单直接,但缺乏对错误类型的判断和更灵活的退避策略。

使用async/await的递归版本

async/await和递归实现,逻辑会更清晰,也更容易添加指数退避等高级特性。

async function retryAsync(fn, maxAttempts, baseDelay = 1000) {
  let lastError;
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    try {
      return await fn();
    } catch (error) {
      lastError = error;
      console.log(`尝试 ${attempt} 失败:`, error.message);
      if (attempt < maxAttempts) {
        const delay = baseDelay * Math.pow(2, attempt - 1); // 指数退避
        await new Promise(r => setTimeout(r, delay));
      }
    }
  }
  throw lastError;
}

这个版本使用for循环和try...catch。它实现了指数退避策略:每次重试的等待时间是指数增长的(1秒、2秒、4秒…),这有助于减轻服务端的压力。最后抛出的错误是最后一次尝试的失败原因。

考虑错误类型与即时重试

并非所有错误都值得重试。例如,HTTP状态码为400的客户端错误,重试多少次也不会成功。一个更完善的实现应该允许调用者指定重试条件。

async function retryWithCondition(fn, maxAttempts, shouldRetry) {
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    try {
      return await fn();
    } catch (error) {
      if (attempt === maxAttempts || !shouldRetry(error)) {
        throw error;
      }
      console.log(`条件重试中,第 ${attempt} 次`);
    }
  }
}

// 只对网络错误或5xx状态码重试
retryWithCondition(unstableTask, 3, (error) => {
  return error.name === 'TypeError' || error.status >= 500;
});

在实际项目中,重试逻辑需要考虑幂等性(操作重复执行是否安全)、取消机制以及日志记录。对于简单的需求,自己实现一个类似retryAsync的函数就足够了。对于复杂的场景,可以考虑使用p-retry这类经过充分测试的第三方库,它们提供了丰富的配置选项。合理的重试机制能显著提升应用在不可靠网络环境下的韧性。

© 版权声明
THE END
喜欢就支持一下吧
点赞6 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容