JavaScript 異步循環(huán) - async/await 的使用方法

如何以順序或并行方式運(yùn)行異步循環(huán)?

在對(duì)循環(huán)進(jìn)行異步處理之前,我想提醒您如何編寫經(jīng)典的同步循環(huán)。

同步循環(huán)

很久以前我也是這樣寫For循環(huán):

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

這樣寫很好,速度很快,但是有很多可讀性和維護(hù)問題。我們可以用它更好的版本:

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

JS語言在開發(fā)中運(yùn)行很快,我們還有更多的功能和新語法,其中一個(gè)是我最常用的 async/await。我現(xiàn)在也經(jīng)常在用,有時(shí)在異步處理數(shù)組的里數(shù)據(jù)時(shí)會(huì)出現(xiàn)這個(gè)問題。

異步循環(huán)

如何在循環(huán)中使用 await ?讓我們編寫異步函數(shù)并 await 每個(gè)任務(wù)。

async function processArray(array) {
  array.forEach(item => {
    // define synchronous anonymous function
    // IT WILL THROW ERROR!
    await func(item);
  })
}

這段代碼會(huì)出現(xiàn)一個(gè)語法錯(cuò)誤,因?yàn)槲覀儾荒茉谕胶瘮?shù)里使用 await 。“processArray”是一個(gè)異步函數(shù),但是我們?cè)谶@個(gè)匿名函數(shù)里用到的 forEach 是同步的。

1.不需要等待結(jié)果

如何修復(fù)之前的問題?我們可以這樣異步定義匿名函數(shù):

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

但是 forEach 不會(huì)等到所有的步驟都完成,它只會(huì)執(zhí)行任務(wù)和執(zhí)行下一步。作為證明我們可以這樣寫一個(gè)簡單例子:

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

async function delayedLog(item) {
  // notice that we can await a function
  // that returns a promise
  await delay();
  console.log(item);
}
async function processArray(array) {
  array.forEach(async (item) => {
    await delayedLog(item);
  })
  console.log('Done!');
}

processArray([1, 2, 3]);

結(jié)果輸出為:

Done!
1
2
3

如果不需要等結(jié)果這樣寫是ok的,但是在大多數(shù)案例里這不是個(gè)很好的邏輯。

2. 線性處理數(shù)組

要等待結(jié)果,我們應(yīng)該返回到老式的 for 循環(huán),但這一次為了更好的可讀性我們可以使用現(xiàn)代寫法 for..of。

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

結(jié)果輸出:

1
2
3
Done!

該代碼將依次處理每一項(xiàng)。但是我們可以使用并行運(yùn)行。

3.并行處理數(shù)組

我們可以稍微修改下代碼然后并行運(yùn)行:

async function processArray(array) {
  // map array to promises
  const promises = array.map(delayedLog);
  // wait until all promises are resolved
  await Promise.all(promises);
  console.log('Done!');
}

這段代碼將并行運(yùn)行許多delayLog 任務(wù)。但是對(duì)于非常大的數(shù)組要小心(并行的任務(wù)太多對(duì)CPU或內(nèi)存來說可能比較吃力)。

也不要混淆“并行”與真正的線程和并行。該代碼不能保證真正的并行執(zhí)行。這取決于您的 item函數(shù)(在本演示中是delayedLog)。網(wǎng)絡(luò)請(qǐng)求、webworker 和其他一些任務(wù)可以并行執(zhí)行。

感謝閱讀!

出處:Anton Lavrenov Blog

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容