You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ES6:在Promise中按条件触发重试直至达到最大重试次数

基于响应条件的Promise灵活重试方案

这确实是个比普通固定重试更贴合实际业务的需求——毕竟很多场景下,咱们不能不管三七二十一就重试,得根据请求返回的结果来决定下一步动作。下面我给你写一个可扩展、基于策略配置的重试实现,完美匹配你提到的场景。

核心思路

把「判断条件」和「对应操作」拆成可配置的策略,主重试函数负责执行目标Promise、循环匹配策略并处理,直到达到最大重试次数或者触发终止条件。

代码实现

首先,先封装一个基于XMLHttpRequest的Promise请求函数(模拟你的场景):

function makeXHRRequest(url) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open('GET', url);
    xhr.onload = () => {
      // 把状态码和响应内容一起返回,方便后续判断
      resolve({
        status: xhr.status,
        responseText: xhr.responseText
      });
    };
    xhr.onerror = () => reject(new Error('XHR请求失败'));
    xhr.send();
  });
}

然后是核心的重试函数,支持自定义策略:

async function retryWithStrategy(
  taskFn, // 要执行的Promise任务函数
  maxRetries, // 最大重试次数
  strategies // 重试策略数组
) {
  let retryCount = 0;

  while (retryCount <= maxRetries) {
    try {
      const result = await taskFn();
      // 遍历策略,找到匹配的规则
      const matchedStrategy = strategies.find(strategy => strategy.condition(result));
      
      if (!matchedStrategy) {
        // 没有匹配到策略,默认返回结果
        return result;
      }

      // 执行策略对应的操作
      const actionResult = await matchedStrategy.action(result);
      
      if (actionResult === 'reject') {
        // 策略要求拒绝,直接抛出错误
        throw new Error(`触发拒绝策略: ${result.status}`);
      } else if (actionResult === 'retry') {
        // 策略要求重试,计数加1,继续循环
        retryCount++;
        console.log(`触发重试策略,当前重试次数: ${retryCount}`);
      } else {
        // 策略返回了新的结果,直接返回
        return actionResult;
      }
    } catch (error) {
      // 捕获到错误,直接拒绝
      throw error;
    }
  }

  // 达到最大重试次数,拒绝
  throw new Error(`已达到最大重试次数: ${maxRetries}`);
}

配置你的专属策略

根据你的需求,配置对应的策略规则:

const customStrategies = [
  // 状态码200:解析Promise,返回结果
  {
    condition: (result) => result.status === 200,
    action: (result) => result
  },
  // 状态码299:立即重试
  {
    condition: (result) => result.status === 299,
    action: () => 'retry'
  },
  // 状态码399:立即拒绝
  {
    condition: (result) => result.status === 399,
    action: () => 'reject'
  },
  // 状态码499:先从服务器获取内容再重试
  {
    condition: (result) => result.status === 499,
    async action() {
      console.log('先从服务器获取额外内容...');
      // 模拟获取额外内容的请求
      const extraData = await fetch('/api/get-extra-content').then(res => res.json());
      console.log('获取到额外内容:', extraData);
      // 返回重试信号
      return 'retry';
    }
  }
];

调用示例

// 模拟一个会返回不同状态码的请求
function mockRequest() {
  // 这里可以根据重试次数模拟不同状态,比如第一次返回499,第二次返回299,第三次返回200
  let callCount = 0;
  return () => {
    callCount++;
    if (callCount === 1) return Promise.resolve({ status: 499 });
    if (callCount === 2) return Promise.resolve({ status: 299 });
    return Promise.resolve({ status: 200, responseText: '成功数据' });
  };
}

// 执行重试
retryWithStrategy(mockRequest(), 3, customStrategies)
  .then(res => console.log('最终结果:', res))
  .catch(err => console.error('请求失败:', err));

扩展性说明

这个方案的扩展性很强,你可以轻松扩展:

  • 给策略加重试间隔:比如在返回'retry'前加await new Promise(resolve => setTimeout(resolve, 1000))
  • 支持更复杂的判断条件:比如根据响应体内容、错误类型来判断
  • 自定义重试次数:给不同策略配置不同的最大重试次数
  • 增加日志、监控:在策略执行前后加入日志打点

内容的提问来源于stack exchange,提问作者sookie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 07:50:54