forEach中使用async/await遇到的问题
Thu Feb 16 2023 Posted 2 years ago
问题描述 #
今天遇到了 forEach
搭配 async/await
使用的问题:
const getTexts = () => {
return Promise.resolve(['1st', '2nd', '3rd'])
}
const addSuffix = (text) => {
return new Promise((resolve, reject) => {
const t = Math.floor((Math.random() * 10) + 1)
setTimeout(() => {
if (text)
resolve(`${text} output`)
else
reject(new Error('text not specified'))
}, t * 1000)
})
}
const forEachAsync = async () => {
console.log('ForEach:')
const texts = await getTexts()
texts.forEach(async (text) => {
const res = await addSuffix(text)
console.log(res)
})
}
forEachAsync()
这段代码期待的结果应该是按顺序依次打印1st 2nd 3rd
,但实际上每次执行 forEachAsync
后打印顺序都是随机的。原因在于 forEach
并不在乎接收的回调函数是一个同步函数还是异步函数,也就是说它的执行流程是同步的,而不会等待 promise
被 resolve/reject
后才执行下一次循环。
通过 forEach
的 polyfill 我们可以明白原因:
Array.prototype.forEach = function (callback) {
// this represents our array
for (let index = 0; index < this.length; index++) {
// We call the callback for each entry
callback(this[index], index, this)
}
}
forEach
内部使用 for
循环来执行异步函数,所以是并行执行。
解决方法 #
方法一 #
使用 for-of
或者 for-in
来替代 forEach
方法二 #
改造 forEach
来使其支持异步函数:
async function asyncForEach(array, callback) {
for (let index = 0; index < array.length; index++)
await callback(array[index], index, array)
}