某條一面異步題解析

前言

這道面試題論在當時我是寫不出來的,當時自吹熟悉promise結果這道題寫不粗來有點尷尬哈哈,面試結束後面試官官讓我再讓我想一下(大概下一面會再考),目前這個寫法大概消耗了一下午的時間去思考吧。javascript

這場面試後續沒完成,由於面以前就已經入職某滴的實習生了。java

題目

//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

// 一開始,一、2兩個任務進入隊列
// 500ms時,2完成,輸出2,任務3進隊
// 800ms時,3完成,輸出3,任務4進隊
// 1000ms時,1完成,輸出1
// 1200ms時,4完成,輸出4
複製代碼

運行過程

@左值爲剩餘時間,右值爲輸出內容面試

執行隊列(最大兩個) 等待隊列 行爲 執行內容
1000@1 執行隊列未滿,直接進入執行隊列 addTask(1000, '1')
1000@一、500@2 執行隊列未滿,直接進入執行隊列 addTask(500, '2')
1000@一、500@2 300@3 執行隊列已滿,加入到等待隊列 addTask(300, '3')
1000@一、500@2 300@三、400@4 執行隊列已滿,加入到等待隊列 addTask(400, '4')
500@一、300@3 400@4 500@2執行完成輸出2,1000@1消耗掉500,從等待隊列按序加入到執行隊列
200@一、400@4 300@3執行完成輸出3,500@1消耗掉300,從等待隊列按序加入到執行隊列
200@4 200@1執行完成輸出1
200@4執行完成輸出4

思路

注意add方法裏面傳入的是函數並返回Promise,這是難點,不少人都是改題,我見過拿getter、setter寫的,我以爲跟題目要考的主旨不一樣。promise

前兩個很好處理,直接判斷執行隊列中是否滿員,未滿直接進隊併發

第三個及之後則須要判斷前二者是否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;
    }
}
複製代碼

缺點與不足

  • 沒法複用ui

    若是調整爲執行隊列最大個數爲3或以上,則須要判斷前n者中是否有resolvethis

  • 容易內存爆炸spa

    list一直保存着primise,不管resolve仍是pedding

  • 異常處理

評論區的問題

基本上全部評論區的的思路都是差很少的。而後就是大部分人沒有考慮拋出原promise的數據問題(學長髮現的),若是實際應用的話,確定要恰數據的嘛,雖然原題沒有提到。

最後

若是有小夥伴還有別的思路或者對缺點有思路的話歡迎評論

相關文章
相關標籤/搜索