JS異步任務的并行、串行及二者結合用法
讓多個異步任務按照我們的想法執(zhí)行,是開發(fā)中常見的需求。今天我們就來捋一下,如何讓多個異步任務并行,串行,以及并行串行相結合。
一、并行
并行是使用最多的方式,多個相互間沒有依賴關系的異步任務,并行執(zhí)行能夠提高效率。
我們最經常用的,是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結束以下幾種數組遍歷方式,同樣可以實現并行。
// forEach遍歷
arr.forEach(item => {
item();
});
// for循環(huán)
for (let i = 0; i < arr.length; i++) {
arr[i]();
}
// for...of遍歷
for (let item of arr) {
item();
}
// 注意,以下兩種寫法同樣是并行的
arr.forEach(async item => await item());
async function f() {
arr.forEach(async item => await item())
}
f();相比之下,Promise.all()可以確保任務都執(zhí)行成功,然后再執(zhí)行后續(xù)操作,這是各種遍歷無法做到的。
另外,還有一種方式也能實現并行:Promise.allSettled()。
Promise.allSettled(arr.map(i => i()));
這種方式很特別,它無法得到每個Promise對象的返回值,卻可以精確得知每個任務的成功還是失敗。如果你有這樣的需求場景,用Promise.allSettled()就很合適。
二、串行
我在工作中遇到過一個場景,一個有1000+元素的數組,每個成員都是調用第三方接口的Promise對象。我像往常一樣得意的使用Promise.all(),等著1000多個任務瞬間完成。然而,結果卻讓我大跌眼鏡,這1000多個任務,只有一部分成功了,大部分都報錯了。不管我執(zhí)行幾次,結果都是這個樣。一籌莫展之后,我才從第三方那兒得知,他們的接口是有調用限制的,一個接口同一時間只能并行300個。
有沒有辦法能讓它們一個接一個的執(zhí)行呢?也就是串行。
nodejs koa框架的next()語法給了我啟發(fā),它就是讓中間件一個接一個的執(zhí)行。于是我想出了遞歸的方式:
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循環(huán)
async function f() {
for (let i = 0; i < arr.length; i++) {
await arr[i]();
}
}
f();發(fā)現了沒?為什么同樣是for循環(huán),同樣是for...of,前面的寫法是并行,后面就成了串行呢?
工作中,我們一定做過這樣的嘗試,想通過遍歷,來讓多個異步任務串行。但往往不得其法,怎么折騰它們都還是同時執(zhí)行。
后一種寫法,你可以理解為:await執(zhí)行完成后,才會進入下一次循環(huán)。 其實,遍歷,就相當于把每一個元素,在代碼中從上到下寫下來。當它們處于async函數中,并在每個元素前面加await,它們自然就能順序執(zhí)行。否則,我們都知道,簡單的順序寫下來的異步任務,它們還是同時執(zhí)行的。
好了,現在程序不報錯了。但是,1000多個任務依次執(zhí)行完成,足足花了十多分鐘,太慢了!有沒有辦法,又快又不觸發(fā)接口調用限制呢?
有,如果可以并行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結束好了,現在可以同時享有并行和串行的好處了!
到此這篇關于JS異步任務的并行、串行,以及二者結合的文章就介紹到這了,更多相關js異步任務并行內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
JavaScript?事件流:從"捕獲"到"冒泡"的完整旅程
這篇文章給大家介紹JavaScript事件流:從“捕獲”到“冒泡”的完整旅程,本文結合實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧2026-05-05
JavaScript返回當前會話cookie全部鍵值對照的方法
這篇文章主要介紹了JavaScript返回當前會話cookie全部鍵值對照的方法,涉及javascript操作cookie的技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-04-04
JavaScript實現橫線提示輸入驗證碼隨輸入驗證碼輸入消失的方法
這篇文章主要介紹了JavaScript實現橫線提示輸入驗證碼隨輸入驗證碼輸入消失的方法,非常實用,在微信開發(fā)中經常會用到,需要的朋友可以參考下2016-09-09

