含async函数调用的for循环未等待内部await执行的问题排查
异步函数在for循环中未等待执行完成的问题分析与解决
问题场景
我有一个包含for循环的函数,循环内调用另一个含await的异步函数,该函数会在异步操作完成后向数组推值,但循环结束后返回的数组是空的,只有异步函数内部的打印能看到数组已更新。
示例代码:
let globalArray = []; const innerFunction = () => { return new Promise((resolve) => { setTimeout(() => { resolve(1); }, 100); }); }; const callingFunction = async () => { let a = await innerFunction(); globalArray.push(a); console.log(`GLOBAL ARRAY AFTER PUSH IN THE CALLING FUCNTION`); console.log(globalArray); }; const outerFunction = () => { for (let i = 0; i < 1; i++) { callingFunction(); console.log(`GLOBAL ARRAY AFTER FUCTION CALL`); console.log(globalArray); } console.log(`GLOBAL ARRAY AFTER FOR LOOP END ${globalArray}`); console.log(globalArray); };
现象
- for循环内部及刚结束时打印
globalArray均为[] callingFunction中push操作后的打印显示globalArray为[1]
期望
所有打印语句都输出globalArray为[1],同时不能大幅改动现有函数的调用模式(每个函数还有其他额外逻辑)。
问题原因
- 异步函数调用未等待:
callingFunction是异步函数,调用它时没有加await,所以for循环会直接执行后续同步代码,完全不等待callingFunction内部的异步操作完成。 - 事件循环机制:
setTimeout属于宏任务,await后的代码会进入微任务队列,所有同步代码(包括for循环内的打印、循环结束后的打印)都会先执行,之后才会处理微任务和宏任务,这就导致同步代码执行时,globalArray还没被push值。
优化实现方式
方式一:修改outerFunction为异步函数(推荐)
只要给outerFunction加上async,并在循环内用await调用callingFunction,就能保证每次循环都等待异步操作完成后再继续,改动极小且保留原有逻辑:
const outerFunction = async () => { for (let i = 0; i < 1; i++) { await callingFunction(); console.log(`GLOBAL ARRAY AFTER FUCTION CALL`); console.log(globalArray); } console.log(`GLOBAL ARRAY AFTER FOR LOOP END ${globalArray}`); console.log(globalArray); };
方式二:用Promise.all批量处理(适合并行执行场景)
如果不需要串行执行每次的callingFunction,可以把所有异步调用收集到Promise数组中,用Promise.all等待全部完成后再执行依赖数组的逻辑:
const outerFunction = () => { const promises = []; for (let i = 0; i < 1; i++) { promises.push(callingFunction()); } Promise.all(promises).then(() => { console.log(`GLOBAL ARRAY AFTER ALL CALLS`); console.log(globalArray); // 所有依赖数组的后续逻辑放到这里 }); };
这种方式适合并行处理所有异步任务的场景,不会阻塞循环,但需要将依赖数组的逻辑放到then回调中。
内容的提问来源于stack exchange,提问作者LoopsMcBeetle
相关产品推荐
相关产品推荐

