基于JS實(shí)現(xiàn)任務(wù)隊(duì)列的示例代碼
引言
假設(shè)有這么一個(gè)場景:
- 前端訂閱后臺(tái)數(shù)據(jù)的變化,如果發(fā)生變化,則觸發(fā)訂閱回調(diào);
- 回調(diào)函數(shù)中,會(huì)執(zhí)行一些耗時(shí)操作,如:請(qǐng)求接口,發(fā)送短信,存歷史數(shù)據(jù)等;
- 要求以上所有的操作都必須按照訂閱觸發(fā)的順序執(zhí)行;
我們都知道,回調(diào)本身就是一種異步操作,我們僅僅依靠訂閱回調(diào)無法保證回調(diào)中任務(wù)執(zhí)行順序的。
為了解決這個(gè)問題,我們可以使用任務(wù)隊(duì)列,將回調(diào)函數(shù)添加到任務(wù)隊(duì)列中,然后按照順序依次執(zhí)行。
任務(wù)隊(duì)列的概念
顧名思義,任務(wù)隊(duì)列就是存放任務(wù)的隊(duì)列,隊(duì)列中的任務(wù)都嚴(yán)格按照進(jìn)入隊(duì)列的先后順序執(zhí)行。
在前一條任務(wù)執(zhí)行完畢后,立即執(zhí)行下一條任務(wù),直到任務(wù)隊(duì)列清空。
任務(wù)隊(duì)列的基本執(zhí)行流程如下:
- 給任務(wù)隊(duì)列添加任務(wù),并判斷執(zhí)行標(biāo)識(shí);
- 如果執(zhí)行標(biāo)識(shí)為 false,則將任務(wù)從隊(duì)列中獨(dú)立出來;
- 開始執(zhí)行任務(wù),將執(zhí)行標(biāo)識(shí)置為 true;
- 執(zhí)行完畢后,判斷隊(duì)列是否為空,如果不為空,則繼續(xù)執(zhí)行下一條任務(wù);
- 直至任務(wù)隊(duì)列清空。
任務(wù)隊(duì)列一直在循環(huán)進(jìn)行如上步驟。
任務(wù)隊(duì)列的 JS 實(shí)現(xiàn)
我們選擇使用數(shù)組來維護(hù)隊(duì)列的執(zhí)行順序,按照“先進(jìn)先出“的原則,依次從數(shù)組的第一個(gè)元素開始往后執(zhí)行。
簡易代碼實(shí)現(xiàn)如下:
/** @format */ class TaskQueue { constructor() { this.queue = []; this.isRunning = false; } /** * @description 將任務(wù)添加至隊(duì)列 * @param {Promise} queueFunction * @returns {undefined} */ addQueue(queueFunction) { this.queue.push(queueFunction); if (!this.isRunning) { this.processQueue(); } } /** * @description 如果隊(duì)列不為空,則開始處理隊(duì)列中的任務(wù),本次任務(wù)執(zhí)行完畢后,立刻開始下一條任務(wù)的執(zhí)行 * @param {} */ processQueue() { if (this.queue.length > 0) { this.isRunning = true; const queueFunction = this.queue.shift(); queueFunction().finally(() => { this.processQueue(); }); } else { this.isRunning = false; } } }
測試
我們使用如下代碼來測試上述實(shí)現(xiàn):
let taskQueue = new TaskQueue(); let f1 = function (name) { return new Promise((resolve) => { setTimeout(() => { console.log(`我是 f1`, name); resolve(); }, 3000); }); }; let f11 = async function () { await f1(" 任務(wù) 1"); }; let f2 = function (name) { return new Promise((resolve) => { setTimeout(() => { console.log(`我是 f2`, name); resolve(); }, 2000); }); }; let f22 = async function () { await f2(" 任務(wù) 2"); }; let f3 = function (name) { return new Promise((resolve) => { setTimeout(() => { console.log(`我是 f3`, name); resolve(); }, 1000); }); }; let f33 = async function () { await f3(" 任務(wù) 3"); }; taskQueue.addQueue(f11); taskQueue.addQueue(f22); taskQueue.addQueue(f33); // 依次輸出: // 我是 f1 任務(wù) 1 // 我是 f2 任務(wù) 2 // 我是 f3 任務(wù) 3
如果不使用任務(wù)隊(duì)列,上面的測試應(yīng)該是按照 f1 -> f2 -> f3 的順序執(zhí)行,但是使用了任務(wù)隊(duì)列之后,f1 -> f2 -> f3 的順序執(zhí)行被改變了,這是因?yàn)槿蝿?wù)隊(duì)列的執(zhí)行順序是按照添加的順序來的,而不是按照?qǐng)?zhí)行順序來的。
總結(jié)
任務(wù)隊(duì)列的實(shí)現(xiàn)非常簡單,但是使用起來卻非常靈活,我們可以根據(jù)實(shí)際需求來決定任務(wù)隊(duì)列的執(zhí)行順序,也可以根據(jù)實(shí)際需求來決定任務(wù)隊(duì)列的執(zhí)行時(shí)機(jī)。
到此這篇關(guān)于基于JS實(shí)現(xiàn)任務(wù)隊(duì)列的示例代碼的文章就介紹到這了,更多相關(guān)JS任務(wù)隊(duì)列內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
教你如何使用firebug調(diào)試功能了解javascript閉包和this
這篇文章主要介紹了教你如何使用firebug調(diào)試功能了解javascript閉包和this,javascript的調(diào)試也是一個(gè)比較大的難點(diǎn),很多基礎(chǔ)的東西都需要自己去摸索,這里將自己的經(jīng)驗(yàn)分享給大家,希望對(duì)大家能夠有所幫助2015-03-03讓div層隨鼠標(biāo)移動(dòng)的實(shí)現(xiàn)代碼 ie ff
隨鼠標(biāo)移動(dòng)的div層使用ie ff ,大家可以注意下兼容性的問題。2009-12-12javascript寫的簡單的計(jì)算器,內(nèi)容很多,方法實(shí)用,推薦
最近用javascript寫了一個(gè)簡單的計(jì)算器,自己測試感覺還好,代碼都給了注釋,非常不錯(cuò),推薦大家學(xué)習(xí)。2011-12-12JavaScript常用截取字符串的三種方式用法區(qū)別實(shí)例解析
本文給大家分享JavaScript常用截取字符串的三種方式及每種用法的區(qū)別解析,感興趣的朋友跟隨腳本之家小編一起看看吧2018-05-05JavaScript?函數(shù)表達(dá)式與函數(shù)聲明的用法及區(qū)別
這篇文章主要介紹了JavaScript?函數(shù)表達(dá)式與函數(shù)聲明詳析,函數(shù)表達(dá)式和函數(shù)聲明是JavaScript中創(chuàng)建函數(shù)的兩種方法,下面文章具體的相關(guān)內(nèi)容介紹,需要的小伙伴可以參考一下2022-06-06JS中實(shí)現(xiàn)函數(shù)return多個(gè)返回值的實(shí)例
下面小編就為大家?guī)硪黄狫S中實(shí)現(xiàn)函數(shù)return多個(gè)返回值的實(shí)例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-02-02