JavaScript 循環:如何處理 async/await

如何串行或者並行運行異步循環?編程

在使用循環處理異步的魔法以前,咱們先來看下咱們是怎麼處理同步循環的。數組

同步循環

好久之前我寫的循環是這樣的:promise

for (var i = 0; i < array.length; i++) {
  var item = array[i];
  //  do something with item
}

後來 JavaScript 提供了不少新的特性,如今咱們會更傾向於用下面這種寫法:異步

array.forEach((item) => {
  //  do something with item
})

在開發過程可能會有這麼一種需求,咱們須要在循環中異步處理 item,那麼能夠怎麼作呢?async

異步循環

如何在循環中使用 await?咱們試着寫一個異步函數,而後 await 每一次循環任務。函數

async function processArray(array) {
  array.forEach(() => {
    //  define synchronous anonymous function
    //  it will throw error here
    await func(item)
  });
}

這個代碼會拋出一個錯誤,由於咱們不能在同步方法中使用 await, processArray 確實是異步函數,可是 array.forEach 裏的匿名函數是同步的。spa

1. 不要等待結果

要處理這個問題,咱們能夠把這個匿名函數定義爲異步的:code

async function processArray(array) {
  array.forEach(() => {
    await delayedLog(item)
  });
  console.log('Done!');
}

可是這樣的話 forEach 方法就至關於異步的了,不會等待遍歷完全部的 item,例以下面這段代碼:對象

function delay () {
  return new Promise(resolve => setTimeout(resolve, 300));
}

async function delayedLog(item) {
  //  notice that we can await a function that returns promise
  await delay();
  //  log item only after a delay 
  console.log(item);
}

async function processArray(array) {
  array.forEach(() => {
    await delayedLog(item)
  });
  console.log('Done!');
}

processArray([1, 2, 3]);

將會輸出:blog

Done!
1
2
3

若是你不須要等待這個循環完成,這樣就已經能夠了。可是大部分狀況咱們仍是須要等待這個循環完成才進行以後的操做。

2. 串行遍歷

要等待全部的結果返回,咱們仍是要回到老式的 for 循環寫法:

async function processArray(array) {
  for (const item of arr) {
    await delayedLog(item);
  }
  console.log('Done!');
}

最後的結果符合咱們的預期:

1
2
3
Done!

上面這段的遍歷代碼是串行執行的,咱們也能夠把它換成並行的。

3. 並行遍歷

咱們能夠稍微更改上面的代碼來編程並行的:

async function processArray(array) {
  //  map() 方法建立一個新數組,其結果是該數組中的每一個元素都調用一個提供的函數後返回的結果。
  //  async 修飾的方法返回值是一個promise對象,所以下面map的返回值就是一個promise列表
  const promiseArr = array.map(delayedLog);
  //  wait until all promises are resolved
  await Promise.all(promiseArr);
  console.log('Done!');
}

(注意:對於特別大的數組不建議使用這種寫法,太多的並行任務會加劇 CPU 和內存的負荷)

 轉自:https://zhuanlan.zhihu.com/p/31000936

相關文章
相關標籤/搜索