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,提问作者Константин Гаврыш
相关产品推荐
相关产品推荐

