实现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
实现一次哈编码

相关文章
相关标签/搜索