JS異步任務的并行、串行,以及二者結合
當前位置:點晴教程→知識管理交流
→『 技術文檔交流 』
讓多個異步任務按照我們的想法執行,是開發中常見的需求。今天我們就來捋一下,如何讓多個異步任務并行,串行,以及并行串行相結合。
一、并行 并行是使用最多的方式,多個相互間沒有依賴關系的異步任務,并行執行能夠提高效率。 我們最經常用的,是Promise.all() 。 function f1() { return new Promise((resolve, reject) => { setTimeout(() => { console.log('1結束'); resolve(); }, 1000) }); } function f2() { return new Promise((resolve, reject) => { setTimeout(() => { console.log('2結束'); resolve(); }, 900) }); } function f3() { return new Promise((resolve, reject) => { setTimeout(() => { console.log('3結束'); resolve(); }, 800) }); } let arr = [f1, f2, f3]; Promise.all(arr.map(i => i()));// 3結束// 2結束// 1結束 以下幾種數組遍歷方式,同樣可以實現并行。 arr.forEach(item => (let i = 0; i < arr.length; i++arr.forEach(async item =>=> 相比之下,Promise.all()可以確保任務都執行成功,然后再執行后續操作,這是各種遍歷無法做到的。 另外,還有一種方式也能實現并行:Promise.allSettled()。 Promise.allSettled(arr.map(i => i())); 這種方式很特別,它無法得到每個Promise對象的返回值,卻可以精確得知每個任務的成功還是失敗。如果你有這樣的需求場景,用Promise.allSettled()就很合適。
二、串行 我在工作中遇到過一個場景,一個有1000+元素的數組,每個成員都是調用第三方接口的Promise對象。我像往常一樣得意的使用Promise.all(),等著1000多個任務瞬間完成。然而,結果卻讓我大跌眼鏡,這1000多個任務,只有一部分成功了,大部分都報錯了。不管我執行幾次,結果都是這個樣。一籌莫展之后,我才從第三方那兒得知,他們的接口是有調用限制的,一個接口同一時間只能并行300個。 有沒有辦法能讓它們一個接一個的執行呢?也就是串行。 nodejs koa框架的next()語法給了我啟發,它就是讓中間件一個接一個的執行。于是我想出了遞歸的方式: async function serial(arr) { let item = arr.shift(); await item(); if (arr.length > 0) { await serial(arr); } } serial(arr);// 1結束// 2結束// 3結束 其實,想讓異步任務串行,不用這么麻煩。以下遍歷的方式,同樣可以實現串行。 // 使用for...of async function f() { for (let item of arr) { await item(); } } f();// 使用for循環 async function f() { for (let i = 0; i < arr.length; i++) { await arr[i](); } } f(); 發現了沒?為什么同樣是for循環,同樣是for...of,前面的寫法是并行,后面就成了串行呢? 工作中,我們一定做過這樣的嘗試,想通過遍歷,來讓多個異步任務串行。但往往不得其法,怎么折騰它們都還是同時執行。 后一種寫法,你可以理解為:await執行完成后,才會進入下一次循環。 其實,遍歷,就相當于把每一個元素,在代碼中從上到下寫下來。當它們處于async函數中,并在每個元素前面加await,它們自然就能串行執行。否則,我們都知道,簡單的從上到下寫下來的異步任務,它們還是并行執行的。 好了,現在程序不報錯了。但是,1000多個任務依次執行完成,足足花了十多分鐘,太慢了!有沒有辦法,又快又不觸發接口調用限制呢? 有,如果可以并行200個任務,完成后再開始下一輪200個......也就是,把并行和串行相結合。
三、并行串行結合 async function bingChuan(arr, num) { let items = arr.splice(0, num); await Promise.all(items.map(i => i())); if (arr.length > 0) { await bingChuan(arr, num); } } bingChuan(arr, 2);// 2結束// 1結束// 3結束 該文章在 2023/10/27 17:42:55 編輯過 |
關鍵字查詢
相關文章
正在查詢... |