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