迴圈使用非同步等待
在迴圈中使用 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) => awaitsomePromiseFn(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);
 });
}