如何在数组循环中正确使用async/await?求最优非阻塞实现方案
遍历数组执行异步任务的正确姿势
你当前forEach写法的问题
你现在用forEach搭配async回调的写法存在隐患:
forEach不会处理异步函数返回的Promise,外层的async函数没法await所有循环里的异步任务完成,这些任务相当于“启动后不管”,你无法知道它们何时全部结束- 如果某个异步操作抛出错误,外层的
try/catch(如果存在)根本捕获不到,因为每个async回调都是独立的Promise实例 - 虽然你加了
await wait(i * 300),但这只是让单个任务内部延迟,所有异步任务还是会被同时启动,并非真正的顺序执行
非阻塞并行执行:Promise.all + map(最优方案)
如果你的需求是尽可能快地完成所有异步任务(非阻塞、并行发起请求),Promise.all搭配map就是最优解。map会把数组每个元素转换成Promise,Promise.all会等待所有Promise完成,外层async函数可以await整个过程,还能统一处理错误。
修改你的代码如下:
if (neighboursArr) { // 用map将每个元素转换为异步任务的Promise const neighbourPromises = neighboursArr.map(async (el, i) => { await wait(i * 300); // 不需要延迟可直接删除该行 const neighbourRes = await fetch(`https://restcountries.com/v3.1/alpha/${el}`); const neighbourData = await neighbourRes.json(); return neighbourData[0]; }); // 等待所有异步任务完成 const allNeighbourData = await Promise.all(neighbourPromises); // 统一渲染结果(也可以在map里直接渲染,不影响并行逻辑) allNeighbourData.forEach(data => renderCountry(data, "neighbour")); } else { renderMessage("It is lonely island :)"); }
如果担心单个请求失败导致整个Promise.all失败,可以改用Promise.allSettled,它会返回所有Promise的执行结果(成功或失败),你可以自行过滤处理。
顺序执行(阻塞式,按顺序完成)
如果你的需求是必须等前一个异步任务完成,再执行下一个,那用for...of循环最稳妥,它天然支持await:
if (neighboursArr) { for (const [i, el] of neighboursArr.entries()) { await wait(i * 300); const neighbourRes = await fetch(`https://restcountries.com/v3.1/alpha/${el}`); const neighbourData = await neighbourRes.json(); renderCountry(neighbourData[0], "neighbour"); } } else { renderMessage("It is lonely island :)"); }
这个写法会严格按照数组顺序执行,每个任务完成后才会进行下一个,外层async函数可以await整个循环过程。
内容的提问来源于stack exchange,提问作者Wick
相关产品推荐
相关产品推荐

