迴圈使用非同步等待
在迴圈中使用 async await 時,你可能會遇到其中一些問題。
如果你只是嘗試在 forEach
中使用 await,這將丟擲 Unexpected token
錯誤。
(async() => {
data = [1, 2, 3, 4, 5];
data.forEach(e => {
const i = await somePromiseFn(e);
console.log(i);
});
})();
這是因為你錯誤地將箭頭函式視為一個塊。await
將在回撥函式的上下文中,而不是 async
。
直譯器保護我們不會出現上述錯誤,但是如果你將 async
新增到 forEach
回撥中,則不會丟擲任何錯誤。你可能認為這解決了問題,但它無法按預期工作。
例:
(async() => {
data = [1, 2, 3, 4, 5];
data.forEach(async(e) => {
const i = await somePromiseFn(e);
console.log(i);
});
console.log('this will print first');
})();
發生這種情況是因為回撥非同步函式只能暫停,而不是父非同步函式。
你可以編寫一個 asyncForEach 函式來返回一個 promise,然後你可以像
await asyncForEach(async (e) => await
somePromiseFn(e), data )
那樣基本上你會返回一個在等待和完成所有回撥時解析的 promise。但是有更好的方法可以做到這一點,那就是使用迴圈。
你可以使用 for-of
迴圈或 for/while
迴圈,你選擇哪一個並不重要。
(async() => {
data = [1, 2, 3, 4, 5];
for (let e of data) {
const i = await somePromiseFn(e);
console.log(i);
}
console.log('this will print last');
})();
但還有另一個問題。此解決方案將等待每次呼叫 somePromiseFn
完成,然後再迭代下一個。
如果你真的希望按順序執行 somePromiseFn
呼叫,但是如果你希望它們同時執行,則需要在 Promise.all
上進行此操作。
(async() => {
data = [1, 2, 3, 4, 5];
const p = await Promise.all(data.map(async(e) => await somePromiseFn(e)));
console.log(...p);
})();
Promise.all
接收一個 promises 陣列作為其唯一引數並返回一個 promise。當解析陣列中的所有 promise 時,也會解析返回的 promise。我們知道這個承諾,當它解決了我們所有的值。
以上示例是完全可執行的。somePromiseFn
函式可以作為具有超時的非同步回顯函式。你可以嘗試使用至少 stage-3
預設的 babel-repl 中的示例並檢視輸出。
function somePromiseFn(n) {
return new Promise((res, rej) => {
setTimeout(() => res(n), 250);
});
}