Array.prototype.forEach 只能接受傳入 Synchronous Function,若要傳入 Asynchronous Function,可依需求使用不同方式實現。
Version
ECMAScript 2017
Synchronous forEach
let data = [1, 2, 3]
data.forEach (x => console.log (x))
console.log ('Finished sync')
forEach 用來處理 side effect,可傳入 sync function,如預期先印出 data,最後印出 Finished sync。

Asynchronous forEach
let data = [1, 2, 3]
let sleep = ms => new Promise (resolve => setTimeout (resolve, ms))
data.forEach (async x => {
await sleep (10 - x)
console.log (x)
})
console.log ('Finished async')
若對 forEach 傳入 async function,會發現 Finished async 先印出,然後才印出 data,且會根據實際 delay 時間印出。

Promise.all + map
let data = [1, 2, 3]
let sleep = ms => new Promise (resolve => setTimeout (resolve, ms))
await Promise.all (data.map (async x => {
await sleep (10 - x)
console.log (x)
}))
console.log ('Finished async')
若需求是 async function 先印出 data,最後才印出 Finished async,則必須改用 Promise.all + map 組合:
map:印出data內每個 element 並回傳 Array PromisePromise.all:確保 Array Promise 內所有 Promise 都執行完,才回傳新 Promise Arrayawait Promise.all:由於Promise.all亦回傳 Promise,因次要加上await確保 async function 都執行完後才印出Finished async

reduce
let data = [1, 2, 3]
let sleep = ms => new Promise (resolve => setTimeout (resolve, ms))
await data.reduce (async (ac, x) => {
await ac
await sleep (10 - x)
console.log (x)
}, 0)
console.log ('Finished async')
若需求是儘管 async function 先印出 data,也要根據 code 執行順序印出,而非根據實際 delay 時間印出,則必須改用 reduce 實現:
await ac:無論 async function 實際 delay 多久,都會被await ac擋住await reduce:由於傳入 async function 回傳 Promise,經過reduce累積後亦回傳 Promise,因次要加上await確保 async function 都執行完後才印出Finished async

for Loop + await
let data = [1, 2, 3]
let sleep = ms => new Promise (resolve => setTimeout (resolve, ms))
for (let x of data) {
await sleep (10 - x)
console.log (x)
}
console.log ('Finished async')
若需求是儘管 async function 先印出 data,也要根據 code 執行順序印出,而非根據實際 delay 時間印出,除了使用 reduce 實現外,也可簡單使用 for loop + await 實現:
await sleep (10 - x):無論sleepdelay 多久,await都會等待sleep執行完,因此不受實際 delay 影響

Conclusion
map與reduce原本不是用來處理 side effect,但由於forEach接受 async function 時有其限制,只好藉由map與reduce實現一些forEach做不到事情- 由於
forEach本來就不是設計用來使用 async function,若需求就是不考慮實際 delay 影響,又覺得使用reduce很 tricky,可改用forloop +await較直覺,這也是少數forloop 較適用場合
Reference
Tamas Sallai, How to use async functions with Array.forEach in JavaScript