JS異步任務(wù)的并行、串行及二者結(jié)合用法
讓多個(gè)異步任務(wù)按照我們的想法執(zhí)行,是開發(fā)中常見的需求。今天我們就來捋一下,如何讓多個(gè)異步任務(wù)并行,串行,以及并行串行相結(jié)合。
一、并行
并行是使用最多的方式,多個(gè)相互間沒有依賴關(guān)系的異步任務(wù),并行執(zhí)行能夠提高效率。
我們最經(jīng)常用的,是Promise.all() 。
function f1() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('1結(jié)束');
resolve();
}, 1000)
});
}
function f2() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('2結(jié)束');
resolve();
}, 900)
});
}
function f3() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('3結(jié)束');
resolve();
}, 800)
});
}
let arr = [f1, f2, f3];
Promise.all(arr.map(i => i()));
// 3結(jié)束
// 2結(jié)束
// 1結(jié)束以下幾種數(shù)組遍歷方式,同樣可以實(shí)現(xiàn)并行。
// 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()可以確保任務(wù)都執(zhí)行成功,然后再執(zhí)行后續(xù)操作,這是各種遍歷無法做到的。
另外,還有一種方式也能實(shí)現(xiàn)并行:Promise.allSettled()。
Promise.allSettled(arr.map(i => i()));
這種方式很特別,它無法得到每個(gè)Promise對(duì)象的返回值,卻可以精確得知每個(gè)任務(wù)的成功還是失敗。如果你有這樣的需求場(chǎng)景,用Promise.allSettled()就很合適。
二、串行
我在工作中遇到過一個(gè)場(chǎng)景,一個(gè)有1000+元素的數(shù)組,每個(gè)成員都是調(diào)用第三方接口的Promise對(duì)象。我像往常一樣得意的使用Promise.all(),等著1000多個(gè)任務(wù)瞬間完成。然而,結(jié)果卻讓我大跌眼鏡,這1000多個(gè)任務(wù),只有一部分成功了,大部分都報(bào)錯(cuò)了。不管我執(zhí)行幾次,結(jié)果都是這個(gè)樣。一籌莫展之后,我才從第三方那兒得知,他們的接口是有調(diào)用限制的,一個(gè)接口同一時(shí)間只能并行300個(gè)。
有沒有辦法能讓它們一個(gè)接一個(gè)的執(zhí)行呢?也就是串行。
nodejs koa框架的next()語法給了我啟發(fā),它就是讓中間件一個(gè)接一個(gè)的執(zhí)行。于是我想出了遞歸的方式:
async function serial(arr) {
let item = arr.shift();
await item();
if (arr.length > 0) {
await serial(arr);
}
}
serial(arr);
// 1結(jié)束
// 2結(jié)束
// 3結(jié)束其實(shí),想讓異步任務(wù)串行,不用這么麻煩。以下遍歷的方式,同樣可以實(shí)現(xiàn)串行。
// 使用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ā)現(xiàn)了沒?為什么同樣是for循環(huán),同樣是for...of,前面的寫法是并行,后面就成了串行呢?
工作中,我們一定做過這樣的嘗試,想通過遍歷,來讓多個(gè)異步任務(wù)串行。但往往不得其法,怎么折騰它們都還是同時(shí)執(zhí)行。
后一種寫法,你可以理解為:await執(zhí)行完成后,才會(huì)進(jìn)入下一次循環(huán)。 其實(shí),遍歷,就相當(dāng)于把每一個(gè)元素,在代碼中從上到下寫下來。當(dāng)它們處于async函數(shù)中,并在每個(gè)元素前面加await,它們自然就能順序執(zhí)行。否則,我們都知道,簡單的順序?qū)懴聛淼漠惒饺蝿?wù),它們還是同時(shí)執(zhí)行的。
好了,現(xiàn)在程序不報(bào)錯(cuò)了。但是,1000多個(gè)任務(wù)依次執(zhí)行完成,足足花了十多分鐘,太慢了!有沒有辦法,又快又不觸發(fā)接口調(diào)用限制呢?
有,如果可以并行200個(gè)任務(wù),完成后再開始下一輪200個(gè)......也就是,把并行和串行相結(jié)合。
三、并行串行結(jié)合
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結(jié)束
// 1結(jié)束
// 3結(jié)束好了,現(xiàn)在可以同時(shí)享有并行和串行的好處了!
到此這篇關(guān)于JS異步任務(wù)的并行、串行,以及二者結(jié)合的文章就介紹到這了,更多相關(guān)js異步任務(wù)并行內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- JavaScript利用生成器函數(shù)實(shí)現(xiàn)優(yōu)雅處理異步任務(wù)流
- JavaScript實(shí)現(xiàn)異步任務(wù)循環(huán)順序執(zhí)行詳解
- 一文帶你簡單封裝JS下的異步任務(wù)對(duì)象
- await-to-js源碼深入理解處理異步任務(wù)用法示例
- JavaScript同步與異步任務(wù)問題詳解
- JavaScript事件循環(huán)同步任務(wù)與異步任務(wù)
- 如何在現(xiàn)代JavaScript中編寫異步任務(wù)
- 如何優(yōu)雅地取消 JavaScript 異步任務(wù)
- 淺談關(guān)于JS下大批量異步任務(wù)按順序執(zhí)行解決方案一點(diǎn)思考
相關(guān)文章
給事件響應(yīng)函數(shù)傳參數(shù)的四種方式小結(jié)
這篇文章主要介紹了給事件響應(yīng)函數(shù)傳參數(shù)的四種方式。需要的朋友可以過來參考下,希望對(duì)大家有所幫助2013-12-12
JavaScript實(shí)現(xiàn)大文件分片上傳處理
這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)大文件分片上傳處理,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08
DWR實(shí)現(xiàn)模擬Google搜索效果實(shí)現(xiàn)原理及代碼
本文主要介紹DWR實(shí)現(xiàn)模擬Google搜索效果實(shí)現(xiàn)原理,感興趣的朋友可以了解下,或許對(duì)你的DWR學(xué)習(xí)有幫助,閑話就不多說了,看代碼了2013-01-01
javascript實(shí)現(xiàn)右側(cè)彈出“分享到”窗口效果
這篇文章主要為大家介紹了javascript實(shí)現(xiàn)右側(cè)彈出“分享到”窗口效果,以一個(gè)完整的js右側(cè)彈出“分享到”窗口的實(shí)例代碼進(jìn)行分析,感興趣的小伙伴們可以參考一下2016-02-02
js判斷移動(dòng)端橫豎屏視口檢測(cè)實(shí)現(xiàn)的幾種方法
最近做歌一個(gè)小項(xiàng)目,但是要放到我們的app上,然而需要橫豎屏使用不同的樣式,本文就來介紹一下js判斷移動(dòng)端橫豎屏視口檢測(cè)實(shí)現(xiàn)的幾種方法,感興趣的可以了解一下2021-07-07
JavaScript中.min.js和.js文件的區(qū)別講解
今天小編就為大家分享一篇關(guān)于JavaScript中.min.js和.js文件的區(qū)別講解,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2019-02-02
JS使用canvas中的measureText方法測(cè)量字體寬度示例
這篇文章主要介紹了JS使用canvas中的measureText方法測(cè)量字體寬度,結(jié)合實(shí)例形式分析了canvas的measureText方法相關(guān)使用技巧,需要的朋友可以參考下2019-02-02
HTML5+Canvas調(diào)用手機(jī)拍照功能實(shí)現(xiàn)圖片上傳(上)
這篇文章主要為大家詳細(xì)介紹了HTML5+Canvas,和jquery技術(shù),調(diào)用手機(jī)拍照功能實(shí)現(xiàn)圖片上傳,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04

