實現Lazyman

前言

以前在掘金上到一篇文章關於微信面試的文章,其中提到了手動實現Lazyman的問題。剛開始
看到Lazyman我是一臉懵逼的,這是什麼鬼,後來查了查了一下,才發現,其實就是手動實現
如下功能:javascript

實現一個LazyMan,能夠按照如下方式調用:
LazyMan(「Hank」)輸出:
Hi! This is Hank!
 
LazyMan(「Hank」).sleep(10).eat(「dinner」)輸出
Hi! This is Hank!
//等待10秒..
Wake up after 10
Eat dinner~
 
LazyMan(「Hank」).eat(「dinner」).eat(「supper」)輸出
Hi This is Hank!
Eat dinner~
Eat supper~
 
LazyMan(「Hank」).sleepFirst(5).eat(「supper」)輸出
//等待5秒
Wake up after 5
Hi This is Hank!
Eat supper
 
以此類推。

看起來好像挺有趣的,咱們來分析如下java

分析

首先咱們看到例子有幾個特色,一個是咱們調用Lazyman的時候不須要用到new關鍵字,這意味着咱們須要使用工廠函數;另外一個是要咱們實現鏈式調用。
咱們看到LazyMan(「Hank」).eat(「dinner」).eat(「supper」)這樣的形式,無疑是鏈式調用了;還有一個難點就是 LazyMan(「Hank」).sleepFirst(5).eat(「supper」)
當存在sleepFirst時,咱們還要先等待一段時間,而後再開始報名字,這就說明sleepFirst優先級更高,無論什麼時候註冊,都要第一個執行,仔細想一想
有什麼能夠實現這個呢?明顯咱們須要一個任務隊列,並且sleepFirst放在最前面,而後等全部任務都安排好了,纔開始執行任務隊列
恩?那說明執行任務不能緊跟在插入任務全程的後面,那咱們見他們分進兩個事件隊列就行了,這就須要藉助setTimeout函數了;
除此以外,一個任務完成了,咱們怎麼通知任務隊列去取下一個任務呢?這就須要一個尾調用。面試

編碼

通過上面的分析,咱們能夠開始編碼了:
首先,咱們先寫工廠函數promise

function Lazyman ( name ) {
    return new _Lazyman ( name );
}

接着咱們開始實現Lazyman:微信

constructor ( name ) {
        this.tasks = [];//設置任務隊列
        let task = (name => () => {
            console.log ( `Hi! This is ${name} !` );
            this.next ();
        }) ( name );
        this.tasks.push ( task );
        //經過settimeout的方法,將執行函數放入下一個事件隊列中,從而達到先註冊事件,後執行的目的

        setTimeout ( () => {
            this.next ();
        }, 0 );

    }
    //尾調用函數,一個任務執行完而後再調用下一個任務
    next () {
        let task = this.tasks.shift ();
        task && task ();
    }

    eat ( food ) {
        let task = (food => () => {
            console.log ( `Eat ${food}` );
            this.next ();
        }) ( food );
        this.tasks.push ( task );
        return this;
    }

    sleep ( time ) {
        let task = (time => () => {
            setTimeout ( () => {
                console.log ( `Wake up after ${time} s!` );
                this.next ();
            }, time * 1000 )
        }) ( time );
        this.tasks.push ( task );
        return this;
    }

    sleepFirst ( time ) {
        let task = (time => () => {
            setTimeout ( () => {
                console.log ( `Wake up after ${time} s!` );
                this.next ();
            }, time * 1000 )
        }) ( time );
        this.tasks.unshift ( task );//sleepFirst函數須要最早執行,因此咱們須要在任務隊列前面放入,而後再執行後面的任務
        return this;
    }

}

經過上面的步驟,咱們就實現了一個簡單的Lazyman了函數

改進

上面明明實現了一個Lazyman了呀,還有什麼能夠改進的?固然有,若是咱們調用eat的時候,想輸出的是Eaaaaaaaaaat ${food}!!!!,而後輸出好飽啊好飽啊
這意味着每次改變,咱們都要去修改eat這個函數,這就耦合度過高了,這時候,咱們能夠採用發佈訂閱的方式,在調用eat的時候,咱們註冊一個監聽函數,而後當任務
執行的時候再發布這個事件,讓對應的監聽函數執行,這樣就實現瞭解耦了this

總結

一個小小的Lazyman,居然有如此多的考點,是在讓人受益不淺,固然,Lazyman還能夠使用promise的方式實現,固然實現一個手寫的Promise實在有點難(逃),有機會再用promise
實現一次哈編碼

相關文章
相關標籤/搜索