JavaScript中forEach循环内使用async await无法得到正确输出如何解决
问题原理说明
Array.prototype.forEach没有对异步回调做特殊处理,它只会同步执行所有传入的回调函数,不会等待回调内的异步逻辑执行完成。你给forEach传入的async函数返回的Promise会被直接忽略,forEach触发完所有回调后就会立即执行后续的console.log(newArr)代码,此时回调里的push逻辑还没执行,自然拿到空数组。setTimeout本身返回的是定时器编号,不是Promise对象,直接用await setTimeout(...)不会产生等待效果,await只会对Promise类型的对象生效,非Promise值会被直接返回,不会暂停当前函数执行。
修复方案
你可以把forEach替换为支持异步等待的for...of循环,同时把setTimeout封装为Promise,示例代码如下:
var arr = [1, 2, 34, 5, 6, 67, 4] var val = 34 var newArr = [] // 封装setTimeout为Promise const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms)) // 外层需要用async函数包裹 async function processArr() { for (const elm of arr) { await delay(10) // 现在await可以正确等待10ms if (val == elm) { newArr.push(elm) } } // 所有异步逻辑执行完成后再打印 console.log(newArr) } processArr()
如果你需要并行处理数组元素提升效率,可以用Promise.all的写法:
var arr = [1, 2, 34, 5, 6, 67, 4] var val = 34 const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms)) async function processArr() { const promises = arr.map(async (elm) => { await delay(10) return val == elm ? elm : null }) const results = await Promise.all(promises) const newArr = results.filter(item => item !== null) console.log(newArr) } processArr()
内容的提问来源于stack exchange,提问作者Tiny Bot
相关产品推荐
相关产品推荐

