一文帶你簡單封裝JS下的異步任務對象
廢話開篇:
js有微任務跟宏任務,但是不管是哪種任務并不代表著會開辟新的線程,可以理解為將上述兩種任務放到“主任務”之后執(zhí)行,有點像iOS下的在主線程調(diào)用異步函數(shù)一樣,其實也只是將異步任務降低了優(yōu)先級,等主線程不忙的時候再處理該任務,比如:UI任務優(yōu)先級較高,所以,任何的主線程下的異步任務都要排到UI任務結束之后進行。
一、利用 Promise 實現(xiàn)異步任務
利用 Promise 實現(xiàn)異步任務,如果不加任何限制,微任務的執(zhí)行便會按添加的先后順序進行執(zhí)行。這里簡單封裝一下,實現(xiàn)微任務下的執(zhí)行依賴??赡苡腥藭?,await 不就行了嗎?是的,聲明異步方法就能滿足,順序執(zhí)行。但是還是要整理一個過程來增加對代碼的理解。
二、實現(xiàn)效果
這里簡單的邏輯是:異步3任務 -> 異步2任務 -> 異步1任務
三、代碼實現(xiàn)
下面是調(diào)度代碼邏輯
function dispath(){ console.log('異步3完成,異步2才能開始,異步2完成,異步1才能開始') //創(chuàng)建任務一 let blockOperationOne = new BlockOperation((b)=>{ console.log('異步1任務'); //單一任務完成事件通知 b.finished(); }); //添加新任務 blockOperationOne.addExecutionBlock((b)=>{ console.log('異步1新增任務'); b.finished(); }); //創(chuàng)建任務二 let blockOperationTwo = new BlockOperation((b)=>{ console.log('異步2任務'); b.finished(); }); blockOperationTwo.addExecutionBlock((b)=>{ console.log('異步2新增任務2'); b.finished(); }); blockOperationTwo.addExecutionBlock((b)=>{ console.log('異步2新增任務需要等待4秒'); setTimeout(() => { console.log('異步2新增任務3'); b.finished(); }, 4000); }); //創(chuàng)建任務三 let blockOperationThree = new BlockOperation((b)=>{ console.log('異步3需要等待1秒'); setTimeout(() => { console.log('異步3任務'); b.finished(); }, 1000); }); //添加依賴 blockOperationOne.addDependency(blockOperationTwo); blockOperationTwo.addDependency(blockOperationThree); //開始執(zhí)行 blockOperationOne.start(); blockOperationTwo.start(); blockOperationThree.start(); console.log('我是宏任務'); };
下面是封裝的 BlockOperation 對象
//任務通知對象 class Block{ //完成回調(diào) doneCallBack = null constructor(doneCallBack){ this.doneCallBack = doneCallBack } //單任務完成 finished(){ this.doneCallBack(); } } //任務對象 class BlockOperation { //任務集合 blocks = [] //是否已開始 isBeginStart = false //依賴任務對象 dependencyOperation = null //被依賴影響的對象 impactOperation = null //全部完成的事件判定 allOperationIsDone = false //全部完成的事件回調(diào) allOperationDoneBlock = ()=>{ //將依賴任務完成進行自身任務 if(this.impactOperation){ this.impactOperation.start() } }; //代理 proxy = null; //代理set方法 handler = { set(target,property,value){ target[property] = value if(property == 'allOperationIsDone' && value){ //執(zhí)行閉包回調(diào) target.allOperationDoneBlock(); } return true }, get(target,property){ return target[property] } } //初始化 constructor(cb){ this.blocks.push(cb) this.addObserver() } //添加觀察者 addObserver(){ this.proxy = new Proxy(this, this.handler) } //添加新任務 addExecutionBlock(cb){ this.blocks.push(cb) } //添加依賴 addDependency(blockOperation){ this.dependencyOperation = blockOperation blockOperation.impactOperation = this } //開始異步任務 start(){ const self = this self.isBeginStart = true //先判斷是否有依賴 if(this.dependencyOperation && this.dependencyOperation.allOperationIsDone == false){ //這里加一個定時器(目的是添加一個相對靠后的宏任務來檢查所有的任務是否都執(zhí)行了開啟,不是很嚴謹) setTimeout(()=>{ if(self.dependencyOperation.isBeginStart == false){ throw Error('請檢查是否有依賴任務未開啟') } },0) //等待依賴的執(zhí)行完 return } self.blocks.forEach((operationBlock) => { Promise.resolve(operationBlock).then((res)=>{ if(res){ res(new Block(()=>{ //刪除任務 delete self.blocks[self.blocks.indexOf(res)] //過濾null(防止delete執(zhí)行后數(shù)組中有null占位) self.blocks = self.blocks.filter((item) => { return item }) //判斷是否全部完成 self.proxy.allOperationIsDone = (self.blocks.length == 0) })) }; }) }); } }
四、總結與思考
其實 async / await 的使用是可以避免回調(diào)的,但是,這里并不是去用它的特性來優(yōu)化代碼,而是用 Promise 的 then 函數(shù)是微任務來處理異步,目的就是將一些不太重要的邏輯放到主任務之后,這里也是參考了 iOS 下的 NSBlockOperation 的一些 api 命名,語言間實現(xiàn)代碼雖然不同,但卻存在著互通的設計思路吧。
到此這篇關于封裝JS下異步任務對象的文章就介紹到這了,更多相關JS異步任務對象封裝內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
JS檢索下拉列表框中被選項目的索引號(selectedIndex)
這篇文章主要介紹了JS檢索下拉列表框中被選項目的索引號(selectedIndex),本文通過實例代碼圖文詳解的形式給大家介紹的非常詳細,需要的朋友可以參考下2019-12-12淺析JavaScript作用域鏈、執(zhí)行上下文與閉包
JavaScript 采用詞法作用域(lexical scoping),函數(shù)執(zhí)行依賴的變量作用域是由函數(shù)定義的時候決定,而不是函數(shù)執(zhí)行的時候決定,通過本文給大家介紹JavaScript作用域鏈、執(zhí)行上下文與閉包相關知識,感興趣的朋友一起學習吧2016-02-02關于js復制內(nèi)容到瀏覽器剪貼板報錯:Cannot read properties of&n
這篇文章主要給大家介紹了關于js復制內(nèi)容到瀏覽器剪貼板報錯:Cannot read properties of undefined (reading ‘writeText‘)的解決方案,文中給出了詳細的原因分析和解決方案,需要的朋友可以參考下2024-01-01JavaScript面向對象知識串結(讀JavaScript高級程序設計(第三版))
最近在看JavaScript高級程序設計(第三版),面向對象一章20多頁,來來回回看了三五遍,每次看的收獲都不一樣2012-07-07