资讯专栏INFORMATION COLUMN

实现Lazyman

Tonny / 3384人阅读

摘要:前言之前在掘金上到一篇文章关于微信面试的文章,其中提到了手动实现的问题。看起来好像挺有趣的,我们来分析以下分析首先我们看到例子有几个特点,一个是我们调用的时候不需要用到关键字,这意味着我们需要使用工厂函数另一个是要我们实现链式调用。

前言

之前在掘金上到一篇文章关于微信面试的文章,其中提到了手动实现Lazyman的问题。刚开始
看到Lazyman我是一脸懵逼的,这是什么鬼,后来查了查了一下,才发现,其实就是手动实现
以下功能:

实现一个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
 
以此类推。

看起来好像挺有趣的,我们来分析以下

分析

首先我们看到例子有几个特点,一个是我们调用Lazyman的时候不需要用到new关键字,这意味着我们需要使用工厂函数;另一个是要我们实现链式调用。
我们看到LazyMan(“Hank”).eat(“dinner”).eat(“supper”)这样的形式,无疑是链式调用了;还有一个难点就是 LazyMan(“Hank”).sleepFirst(5).eat(“supper”)
当存在sleepFirst时,我们还要先等待一段时间,然后再开始报名字,这就说明sleepFirst优先级更高,不管何时注册,都要第一个执行,仔细想想
有什么可以实现这个呢?明显我们需要一个任务队列,而且sleepFirst放在最前面,然后等所有任务都安排好了,才开始执行任务队列
恩?那说明执行任务不能紧跟在插入任务全程的后面,那我们见他们分进两个事件队列就好了,这就需要借助setTimeout函数了;
除此之外,一个任务完成了,我们怎么通知任务队列去取下一个任务呢?这就需要一个尾调用。

编码

经过上面的分析,我们可以开始编码了:
首先,我们先写工厂函数

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的时候,我们注册一个监听函数,然后当任务
执行的时候再发布这个事件,让对应的监听函数执行,这样就实现了解耦了

总结

一个小小的Lazyman,竟然有如此多的考点,是在让人受益匪浅,当然,Lazyman还可以使用promise的方式实现,当然实现一个手写的Promise实在有点难(逃),有机会再用promise
实现一次哈

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/88231.html

相关文章

  • LazyMan代码实现

    摘要:只需要返回对象本身就可以了。这里只实现一个示例实现链式调用从队列头部插入最后一步封装还有一个大家可以来试一试。如果有想法的话欢迎提出大家交流一下 ES5实现LazyMan lazyman主要原理是: 需要一个队列保存将要用到的事件 利用闭包将事件保存至队列中 创建一个中间件next用来触发事件 链式调用 使用lazyman需要实现的场景: LazyMan(Tom); // my n...

    yhaolpz 评论0 收藏0
  • 如何实现一个 LazyMan?

    摘要:实现一个,可以按照以下方式调用输出输出等待秒输出输出等待秒以此类推。这是典型的流程控制,问题的关键是如何实现任务的顺序执行。 实现一个LazyMan,可以按照以下方式调用: LazyMan(Hank)输出: Hi! This is Hank! LazyMan(Hank).sleep(10).eat(dinner)输出 Hi! This is H...

    diabloneo 评论0 收藏0
  • 如何实现一个 LazyMan?

    摘要:实现一个,可以按照以下方式调用输出输出等待秒输出输出等待秒以此类推。这是典型的流程控制,问题的关键是如何实现任务的顺序执行。 实现一个LazyMan,可以按照以下方式调用: LazyMan(Hank)输出: Hi! This is Hank! LazyMan(Hank).sleep(10).eat(dinner)输出 Hi! This is H...

    frank_fun 评论0 收藏0
  • 如何实现一个 LazyMan?

    摘要:实现一个,可以按照以下方式调用输出输出等待秒输出输出等待秒以此类推。这是典型的流程控制,问题的关键是如何实现任务的顺序执行。 实现一个LazyMan,可以按照以下方式调用: LazyMan(Hank)输出: Hi! This is Hank! LazyMan(Hank).sleep(10).eat(dinner)输出 Hi! This is H...

    tianyu 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<