問題描述
在進行業務開發的過程中,使用了陣列的高階函式map
,同時使用了ES6語法async/await
,發現在map
迴圈下任務是非同步執行的,並不符合預期
例子說明
/**
* 非同步列印資料
*/
const echo = async (i) => {
return new Promise((resolve,reject)=>{
setTimeout(() => {
console.log(`i===>`, i,new Date().toLocaleTimeString());
resolve(i) ;
}, 100);
})
}
/**
* 模擬非同步任務
*/
const task = async () => {
dataArr.forEach( async( item, i ) => {
await echo(i);
})
}
/**
* 啟動函式入口
*/
const run = async () => {
console.log(`run-start====>date:`, new Date().toLocaleDateString())
await task() ;
console.log(`run-end======>date:`, new Date().toLocaleDateString())
}
/**
* 啟動函式
*/
(async () => {
console.log(`start...`)
await run();
console.log(`end...`)
})()
//預期效果
start...
run-start====>date: 2019-2-16
i===> 0 23:19:04
i===> 1 23:19:04
i===> 2 23:19:04
i===> 3 23:19:04
run-end======>date: 2019-2-16
end...
//列印結果
start...
run-start====>date: 2019-2-16
run-end======>date: 2019-2-16
end...
i===> 0 23:19:04
i===> 1 23:19:04
i===> 2 23:19:04
i===> 3 23:19:04
從上面的例子可以看出,在map
迴圈下使用await
後, 函式結束標誌訊號run-end
先於非同步任務資料i
輸出,故task任務仍然是非同步執行,並不符合預期。原因是Array的迴圈方法map、forEach、filter、reduce、some、every等是並行迭代
,可以理解為async/await
的效果是無效的
解決方案
- 使用最原始的for迴圈
- for…of
將上述的模擬非同步任務修改為
for (var i = 0; i < dataArr.length; i++) {
await echo(i)
}
或
for (const i of dataArr) {
await echo(i)
}
參考連線
用 async/await 來處理非同步
await在forEach不起作用解決
JavaScript 非同步迴圈 – async/await 的使用方法