前言
這道面試題論在當時我是寫不出來的,當時自吹熟悉promise結果這道題寫不粗來有點尷尬哈哈,面試結束後面試官官讓我再讓我想一下(大概下一面會再考),目前這個寫法大概消耗了一下午的時間去思考吧。
這場面試後續沒完成,因為面之前就已經入職某滴的實習生了。
題目
//JS實現一個帶併發限制的非同步排程器Scheduler,保證同時執行的任務最多有兩個。完善程式碼中Scheduler類,使得以下程式能正確輸出
class Scheduler {
add(promiseCreator) { ... }
// ...
}
const timeout = (time) => new Promise(resolve => {
setTimeout(resolve, time)
})
const scheduler = new Scheduler()
const addTask = (time, order) => {
scheduler.add(() => timeout(time))
.then(() => console.log(order))
}
addTask(1000, '1')
addTask(500, '2')
addTask(300, '3')
addTask(400, '4')
// output: 2 3 1 4
// 一開始,1、2兩個任務進入佇列
// 500ms時,2完成,輸出2,任務3進隊
// 800ms時,3完成,輸出3,任務4進隊
// 1000ms時,1完成,輸出1
// 1200ms時,4完成,輸出4
複製程式碼
執行過程
@左值為剩餘時間,右值為輸出內容
執行佇列(最大兩個) | 等待佇列 | 行為 | 執行內容 |
---|---|---|---|
1000@1 | 執行佇列未滿,直接進入執行佇列 | addTask(1000, '1') | |
1000@1、500@2 | 執行佇列未滿,直接進入執行佇列 | addTask(500, '2') | |
1000@1、500@2 | 300@3 | 執行佇列已滿,加入到等待佇列 | addTask(300, '3') |
1000@1、500@2 | 300@3、400@4 | 執行佇列已滿,加入到等待佇列 | addTask(400, '4') |
500@1、300@3 | 400@4 | 500@2執行完成輸出2,1000@1消耗掉500,從等待佇列按序加入到執行佇列 | |
200@1、400@4 | 300@3執行完成輸出3,500@1消耗掉300,從等待佇列按序加入到執行佇列 | ||
200@4 | 200@1執行完成輸出1 | ||
200@4執行完成輸出4 |
思路
注意add方法裡面傳入的是函式並返回Promise,這是難點,很多人都是改題,我見過拿getter、setter寫的,我覺得跟題目要考的主旨不同。
前兩個很好處理,直接判斷執行佇列中是否滿員,未滿直接進隊
第三個及以後則需要判斷前兩者是否resolve,注意這裡前兩者和前兩個的概念不同(由於是一層抽象,這裡舉例說明:目前處於第三個,那麼前兩者的前者指第一個到第一個,後者指第二個;目前處於第四個,那麼前兩者的前者指第一個到第二個,後者指第三個;以此類推),resolve後從等待佇列按順序加入到執行佇列。
說下原因,有兩種情況。前者先完成,也就是集合中的任務全部執行完成,那麼後者一定會進入執行(未完成),那麼執行佇列中一定會剩下一個位置;後者先完成,這個沒什麼可說的,後者完成後一定會剩下一個位置。
程式碼
class Scheduler {
constructor() {
this.list=[] //promise list
this.cur=0 //current position
this.max=2
}
add(promiseCreator) {
let temp=null;
if(this.cur < this.max) {
temp=promiseCreator();
}else {
let arr=this.list.slice(0,this.cur-1);
let all=Promise.all(arr);
temp=Promise.race([all,this.list[this.cur-1]])
.then(() => {
return promiseCreator();
});
}
this.list.push(temp);
this.cur++;
return temp;
}
}
複製程式碼
缺點與不足
-
無法複用
如果調整為執行佇列最大個數為3或以上,則需要判斷前n者中是否有resolve
-
容易記憶體爆炸
list一直儲存著primise,無論resolve還是pedding
-
異常處理
評論區的問題
基本上所有評論區的的思路都是差不多的。然後就是大部分人沒有考慮丟擲原promise的資料問題(學長發現的),如果實際應用的話,肯定要恰資料的嘛,雖然原題沒有提到。
最後
如果有小夥伴還有別的思路或者對缺點有思路的話歡迎評論