JavaScript實(shí)現(xiàn)異步任務(wù)循環(huán)順序執(zhí)行詳解
需求場(chǎng)景:數(shù)組的元素作為異步任務(wù)的參數(shù),循環(huán)遍歷該數(shù)組,并執(zhí)行異步任務(wù)。
一、錯(cuò)誤的實(shí)現(xiàn)
簡(jiǎn)單的錯(cuò)誤實(shí)現(xiàn)
// 異步任務(wù)的參數(shù)數(shù)組 const arr = [1, 2, 3, 4]; // 異步任務(wù)函數(shù) function task(params, callback) { setTimeout(() => { if (!!callback) { callback(params); } }, 1000); } // 循環(huán)遍歷異步任務(wù)的參數(shù)數(shù)組,并執(zhí)行異步任務(wù) console.time("Test code"); arr.forEach((item, index) => { task(item, (ret) => { console.log("ret", ret); console.timeEnd("Test code"); if (index + 1 < arr.length) { console.time("Test code"); } }); });
執(zhí)行結(jié)果輸出:
由上圖可知,所有異步任務(wù)的執(zhí)行是同時(shí)開始,并同時(shí)結(jié)束的,并未按順序先后執(zhí)行。
使用 Promise.all 的錯(cuò)誤實(shí)現(xiàn)
Promise.all() 是一個(gè)用于并行執(zhí)行多個(gè) Promise 的方法,當(dāng)所有的 Promise 都成功執(zhí)行后,它返回一個(gè)包含所有 Promise 結(jié)果的數(shù)組,如果其中任何一個(gè) Promise 失敗或出錯(cuò),它將直接跳轉(zhuǎn)到 catch 塊中返回一個(gè) rejected 狀態(tài)的 Promise。
// 異步任務(wù)的參數(shù)數(shù)組 const arr = [1, 2, 3, 4]; // 異步任務(wù)函數(shù) function task(params, callback) { setTimeout(() => { if (!!callback) { callback(params); } }, 1000); } const tasks = []; // 循環(huán)遍歷異步任務(wù)的參數(shù)數(shù)組,并執(zhí)行異步任務(wù) console.time("Test code"); arr.forEach((item, index) => { tasks.push( new Promise((resolve) => { task(item, (ret) => { console.log("ret", ret); console.timeEnd("Test code"); if (index + 1 < arr.length) { console.time("Test code"); } resolve(ret); }); }) ); }); Promise.all(tasks) .then((values) => { console.log(values); }) .catch((error) => { console.error(error); });
執(zhí)行結(jié)果輸出:
由上圖可知,循環(huán)中的所有異步任務(wù)的執(zhí)行是并行執(zhí)行的,并未按順序先后執(zhí)行。因?yàn)?Promise.all() 方法的執(zhí)行順序是并行執(zhí)行的,而不是按照 Promise 在數(shù)組中的順序執(zhí)行的。
二、正確的實(shí)現(xiàn)
// 異步任務(wù)的參數(shù)數(shù)組 const arr = [1, 2, 3, 4]; // 異步任務(wù)函數(shù) function task(params, callback) { setTimeout(() => { if (!!callback) { callback(params); } }, 1000); } const tasks = []; console.time("Test code"); arr.forEach((item, index) => { tasks.push(function () { return new Promise((resolve) => { task(item, (ret) => { console.log("ret", ret); console.timeEnd("Test code"); if (index + 1 < arr.length) { console.time("Test code"); } resolve(ret); }); }); }); }); // 定義一個(gè)遞歸函數(shù)來依次執(zhí)行任務(wù) function runTasks(index) { if (index >= tasks.length) { // 如果所有任務(wù)都已經(jīng)執(zhí)行完畢,返回一個(gè) resolved 的 Promise return Promise.resolve(); } // 執(zhí)行當(dāng)前任務(wù),然后遞歸執(zhí)行下一個(gè)任務(wù) return tasks[index]().then(function () { return runTasks(index + 1); }); } // 調(diào)用遞歸函數(shù)來執(zhí)行任務(wù) runTasks(0) .then(function () { console.log("All tasks are done!"); }) .catch(function (error) { console.error(error); });
執(zhí)行結(jié)果輸出:
到此這篇關(guān)于JavaScript實(shí)現(xiàn)異步任務(wù)循環(huán)順序執(zhí)行詳解的文章就介紹到這了,更多相關(guān)JavaScript異步任務(wù)循環(huán)順序執(zhí)行內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JavaScript拆分字符串時(shí)產(chǎn)生空字符的解決方案
使用JavaScript的split方法拆分字符串時(shí)出現(xiàn)一些空字符串"",尤其是當(dāng)使用正則表達(dá)式作為分隔符的時(shí)候。那么,產(chǎn)生這些空字符串的原因是什么?又該如何來處理呢,這就是今天我們要探討的問題2014-09-09Javascript中獲取瀏覽器類型和操作系統(tǒng)版本等客戶端信息常用代碼
跟蹤一些最基本的客戶端訪問信息,這里將一些公用的代碼總結(jié)下來,需要的朋友可以參考下2016-06-06詳解CocosCreator系統(tǒng)事件是怎么產(chǎn)生及觸發(fā)的
這篇文章主要介紹了CocosCreator系統(tǒng)事件是怎么產(chǎn)生及觸發(fā)的,雖然內(nèi)容不少,但是只要一點(diǎn)點(diǎn)抽絲剝繭,具體分析其內(nèi)容,就會(huì)豁然開朗2021-04-04javascript 限制輸入和粘貼(IE和火狐3.x下測(cè)試通過)
限制輸入和粘貼的js代碼2008-11-11JS實(shí)現(xiàn)點(diǎn)擊顏色塊切換指定區(qū)域背景顏色的方法
這篇文章主要介紹了JS實(shí)現(xiàn)點(diǎn)擊顏色塊切換指定區(qū)域背景顏色的方法,涉及javascript操作cookie及背景色的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-02-02javascript typeof的用法與typeof運(yùn)算符介紹[詳細(xì)]
下面是對(duì)于typeof運(yùn)算符的詳細(xì)介紹跟typeof的一些用法,分析,學(xué)習(xí)typeof的朋友,看完了,這篇應(yīng)該能有所收獲。2008-10-10