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

JS使用Promise.race获取最快成功响应、忽略失败请求的实现问题

核心问题说明

你现有代码存在两个关键逻辑错误,导致无法实现预期需求:

  • 用错了Promise方法:Promise.race()只会返回第一个状态变更的Promise结果,不管是成功还是失败,既不能自动忽略失败请求,也拿不到前3个返回结果
  • 错误处理逻辑失效:response.ok为false时,你在setTimeout回调里写的Promise.reject不会被外层then链捕获——setTimeout的回调是独立异步执行的,它的返回值和外层Promise链没有关联,这个分支既没有正确抛出错误,还会继续往下执行response.json()触发解析报错
  • Chrome Network面板能看到所有请求是正常现象:要筛选最快的3个响应,必须先把所有请求都发出,再按返回顺序筛选,不存在只发3个请求就能预判哪3个最快的可能

实现方案

要实现「忽略所有失败请求、获取最先返回的3个成功响应」,不能直接套用Promise.all/Promise.race/Promise.any这些原生方法,需要手动控制请求进度:

  • 给每个详情请求单独加catch兜底,失败的请求直接跳过,不中断整体流程
  • 维护成功结果队列,每收到一个成功响应就入队,凑够3个就立刻返回最终结果
  • 加兜底逻辑:如果所有请求都完成后成功数不足3个,就返回已拿到的所有成功结果,避免Promise挂起

修正后可运行代码
const url = 'https://mate-academy.github.io/phone-catalogue-static/api/phones.json';
const detailsUrl = 'https://mate-academy.github.io/phone-catalogue-static/api/phones/';

const getPhones = () => {
  return fetch(url)
    .then(response => {
      if (!response.ok) {
        // 直接抛出错误才能被catch链路捕获
        throw new Error('It was an accident');
      }
      return response.json();
    });
};

/**
 * 获取最先返回的N个成功请求结果
 * @param {string[]} ids 手机ID列表
 * @param {number} count 需要获取的最快结果数量,默认取3
 * @returns {Promise<Array>} 最快返回的成功结果数组
 */
const getFastestSuccessDetails = (ids, count = 3) => {
  return new Promise((resolve) => {
    const successResults = [];
    const targetCount = Math.min(ids.length, count);
    let settledRequestNum = 0;

    ids.forEach(id => {
      fetch(`${detailsUrl}${id}.json`)
        .then(res => {
          if (!res.ok) throw new Error(`请求${id}失败`);
          return res.json();
        })
        .then(detail => {
          // 已经凑够目标数量就不再处理后续返回
          if (successResults.length >= targetCount) return;
          successResults.push(detail);
          // 凑够数量立刻返回,不需要等剩余慢请求
          if (successResults.length === targetCount) {
            resolve(successResults);
          }
        })
        .catch(err => {
          // 静默忽略失败请求,仅打印日志
          console.warn(`跳过失败请求: ${id}`, err);
        })
        .finally(() => {
          settledRequestNum++;
          // 所有请求都处理完还没凑够数量,返回已有的成功结果
          if (settledRequestNum === ids.length && successResults.length < targetCount) {
            resolve(successResults);
          }
        });
    });
  });
};

// 业务调用
getPhones()
  .then(phones => {
    const ids = phones.map(p => p.id);
    return getFastestSuccessDetails(ids, 3);
  })
  .then(top3Details => {
    console.log('最先返回的3个手机详情:', top3Details);
    // 这里写后续业务逻辑
  })
  .catch(error => {
    console.warn('全局请求异常:', error);
  });

内容的提问来源于stack exchange,提问作者Константин Гаврыш

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 02:01:03