Node中如何用Promise/Async实现UFC选手ID批量查询详情?
嘿,我完全懂这种刚开始摸Async/Promise的困惑——明明知道概念,但一到具体场景就不知道怎么串起来对吧?别慌,针对你的UFC选手数据需求,咱们一步步拆解出清晰的实现方案,保证你看完就能上手。
第一步:先把getFighterId()改成能“通知你数组填完”的异步函数
首先得明确:如果你的UFC选手名单JSON是通过异步方式获取的(比如网络请求、本地文件读取),那原来的函数直接返回数组肯定是空的——因为异步操作还没跑完呢。所以我们要让这个函数返回一个Promise,等数组真的填充完成后再把结果交出来。
用Async/Await改写(最直观的写法)
async function getFighterId() { try { const fighterIds = []; // 这里替换成你实际获取选手名单的异步操作 // 比如从接口拉取: const res = await fetch('ufc-fighter-list.json'); if (!res.ok) throw new Error('选手名单拉取失败'); const fighterList = await res.json(); // 遍历填充ID数组 fighterList.forEach(fighter => fighterIds.push(fighter.id)); return fighterIds; // Async函数会自动把这个值包装成Promise } catch (err) { console.error('获取ID时出错:', err); throw err; // 把错误抛出去,让调用方处理 } }
如果你的JSON是已经存在内存里的静态数据(完全同步),那这一步可以简化,但大部分场景都是异步的,所以重点还是按异步处理。
第二步:写一个获取单选手详情的异步函数
同样,查询选手详情肯定也是异步操作(比如调用接口),我们把它封装成单独的函数:
async function getFighterDetails(fighterId) { try { const res = await fetch(`/api/ufc-fighters/${fighterId}`); if (!res.ok) throw new Error(`ID为${fighterId}的选手详情拉取失败`); return await res.json(); } catch (err) { console.error(err); return null; // 出错时返回null,后续可以过滤掉无效数据 } }
第三步:等ID数组就绪后,批量获取选手详情
这里分两种常用场景,你可以根据需求选:
场景1:串行请求(逐个获取,适合怕接口限流的情况)
就是等前一个选手详情拉完,再拉下一个,不会一下子给服务器发太多请求:
async function fetchAllFighters() { try { // 关键:先await getFighterId(),确保ID数组完全填充 const allFighterIds = await getFighterId(); console.log('所有选手ID已就绪:', allFighterIds); const allFighterDetails = []; // 用for...of循环串行处理(不能用forEach,因为forEach不支持await) for (const id of allFighterIds) { const details = await getFighterDetails(id); if (details) allFighterDetails.push(details); } console.log('所有选手详情已获取:', allFighterDetails); return allFighterDetails; } catch (err) { console.error('整体流程出错:', err); } } // 启动整个流程 fetchAllFighters();
场景2:并行请求(同时发起所有请求,效率更高)
如果你的服务器允许并发请求,这种方式速度会快很多,用Promise.all()实现:
async function fetchAllFighters() { try { const allFighterIds = await getFighterId(); console.log('所有选手ID已就绪:', allFighterIds); // 把每个ID转换成获取详情的Promise const detailPromises = allFighterIds.map(id => getFighterDetails(id)); // 等待所有Promise完成,拿到结果数组 const allFighterDetails = await Promise.all(detailPromises); // 过滤掉可能为null的错误结果 const validDetails = allFighterDetails.filter(d => d !== null); console.log('所有有效选手详情已获取:', validDetails); return validDetails; } catch (err) { console.error('整体流程出错:', err); } } fetchAllFighters();
进阶:分批并行(兼顾速度和限流)
如果ID数量特别多(比如几百个),直接并行可能会被服务器拦截,这时候可以分批发起请求:
async function fetchAllFightersInBatches(batchSize = 5) { try { const allFighterIds = await getFighterId(); const allFighterDetails = []; // 按批次分割ID数组 for (let i = 0; i < allFighterIds.length; i += batchSize) { const batchIds = allFighterIds.slice(i, i + batchSize); const batchPromises = batchIds.map(id => getFighterDetails(id)); const batchResults = await Promise.all(batchPromises); allFighterDetails.push(...batchResults.filter(d => d !== null)); console.log(`已完成第${Math.floor(i/batchSize)+1}批请求`); } console.log('所有选手详情已获取:', allFighterDetails); return allFighterDetails; } catch (err) { console.error('整体流程出错:', err); } } // 每批请求5个选手 fetchAllFightersInBatches(5);
核心逻辑总结
- 所有异步操作都要通过
Promise(或Async/Await语法糖)来标记完成状态 - 必须等
getFighterId()的Promise resolve(也就是数组填充完成)后,再执行后续的详情查询 - 串行/并行/分批并行的选择,取决于你的服务器并发限制和速度需求
内容的提问来源于stack exchange,提问作者Nate Jahnke
相关产品推荐
相关产品推荐

