一文帶你簡單封裝JS下的異步任務(wù)對象
廢話開篇:
js有微任務(wù)跟宏任務(wù),但是不管是哪種任務(wù)并不代表著會開辟新的線程,可以理解為將上述兩種任務(wù)放到“主任務(wù)”之后執(zhí)行,有點像iOS下的在主線程調(diào)用異步函數(shù)一樣,其實也只是將異步任務(wù)降低了優(yōu)先級,等主線程不忙的時候再處理該任務(wù),比如:UI任務(wù)優(yōu)先級較高,所以,任何的主線程下的異步任務(wù)都要排到UI任務(wù)結(jié)束之后進行。
一、利用 Promise 實現(xiàn)異步任務(wù)
利用 Promise 實現(xiàn)異步任務(wù),如果不加任何限制,微任務(wù)的執(zhí)行便會按添加的先后順序進行執(zhí)行。這里簡單封裝一下,實現(xiàn)微任務(wù)下的執(zhí)行依賴??赡苡腥藭?,await 不就行了嗎?是的,聲明異步方法就能滿足,順序執(zhí)行。但是還是要整理一個過程來增加對代碼的理解。
二、實現(xiàn)效果
這里簡單的邏輯是:異步3任務(wù) -> 異步2任務(wù) -> 異步1任務(wù)

三、代碼實現(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ù)完成進行自身任務(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){
//這里加一個定時器(目的是添加一個相對靠后的宏任務(wù)來檢查所有的任務(wù)是否都執(zhí)行了開啟,不是很嚴謹)
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é)與思考
其實 async / await 的使用是可以避免回調(diào)的,但是,這里并不是去用它的特性來優(yōu)化代碼,而是用 Promise 的 then 函數(shù)是微任務(wù)來處理異步,目的就是將一些不太重要的邏輯放到主任務(wù)之后,這里也是參考了 iOS 下的 NSBlockOperation 的一些 api 命名,語言間實現(xiàn)代碼雖然不同,但卻存在著互通的設(shè)計思路吧。
到此這篇關(guān)于封裝JS下異步任務(wù)對象的文章就介紹到這了,更多相關(guān)JS異步任務(wù)對象封裝內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JS檢索下拉列表框中被選項目的索引號(selectedIndex)
這篇文章主要介紹了JS檢索下拉列表框中被選項目的索引號(selectedIndex),本文通過實例代碼圖文詳解的形式給大家介紹的非常詳細,需要的朋友可以參考下2019-12-12
淺析JavaScript作用域鏈、執(zhí)行上下文與閉包
JavaScript 采用詞法作用域(lexical scoping),函數(shù)執(zhí)行依賴的變量作用域是由函數(shù)定義的時候決定,而不是函數(shù)執(zhí)行的時候決定,通過本文給大家介紹JavaScript作用域鏈、執(zhí)行上下文與閉包相關(guān)知識,感興趣的朋友一起學(xué)習(xí)吧2016-02-02
關(guān)于js復(fù)制內(nèi)容到瀏覽器剪貼板報錯:Cannot read properties of&n
這篇文章主要給大家介紹了關(guān)于js復(fù)制內(nèi)容到瀏覽器剪貼板報錯:Cannot read properties of undefined (reading ‘writeText‘)的解決方案,文中給出了詳細的原因分析和解決方案,需要的朋友可以參考下2024-01-01
JavaScript面向?qū)ο笾R串結(jié)(讀JavaScript高級程序設(shè)計(第三版))
最近在看JavaScript高級程序設(shè)計(第三版),面向?qū)ο笠徽?0多頁,來來回回看了三五遍,每次看的收獲都不一樣2012-07-07

