Node.js中异步循环未等待Promise完成的问题解决咨询
异步循环中数组未更新问题的解决方案
问题场景
我有一个名为srtHandler的异步函数,调用procureDuration获取MP3时长并推入script数组,但后续打印script时发现新值未被添加——尽管用了await,程序还是没等异步操作完成就继续执行了。
原代码片段:
const srtHandler = async (req, res) => { elements.forEach(async (num) => { const duration = await procureDuration(file, elementNames[num]); script[num].push(duration); console.log('>', script[num]); // 一堆其他操作 console.log(script) // 这里显示script数组没更新 }); }; const procureDuration = async (file, elementName) => { let duration = await getDuration(file, elementName); console.log({duration}); return duration; }; const getDuration = (subdirectory, file) => { console.log('getting duration of an MP3 file'); const directoryPath = path.join(__dirname, `../data/${subdirectory}/${file}`); return new Promise((resolve, reject) => { mp3Duration(directoryPath, (err, duration) => { if (err) { console.log('error=', 'err'); reject(err); } else { resolve(duration); } }); }); };
问题根源
核心问题是**forEach不支持等待异步回调**。你传入的async (num) => {}会被当作独立的Promise,forEach会快速遍历完所有元素,完全不会等待每个回调里的await procureDuration执行完成。所以当你打印script时,大部分异步操作还在后台运行,数组自然没被更新。
解决方案
方案1:用for...of循环(顺序执行)
for...of是支持异步等待的循环结构,能确保每个异步操作完成后再执行下一次循环:
const srtHandler = async (req, res) => { // 遍历elements中的每个索引num for (const num of elements) { const duration = await procureDuration(file, elementNames[num]); script[num].push(duration); console.log('>', script[num]); // 一堆其他操作 console.log(script); // 此时数组已更新 } };
方案2:用Promise.all结合map(并行执行,效率更高)
如果不需要严格按顺序执行异步操作,用这种方式可以让所有异步请求同时发起,大幅提升效率:
const srtHandler = async (req, res) => { // 将每个异步操作转为Promise,用Promise.all等待全部完成 await Promise.all(elements.map(async (num) => { const duration = await procureDuration(file, elementNames[num]); script[num].push(duration); console.log('>', script[num]); // 一堆其他操作 })); // 所有异步操作完成后再打印数组 console.log(script); };
内容的提问来源于stack exchange,提问作者Bragon
相关产品推荐
相关产品推荐

