考察知识点:闭包,事件轮询机制,链式调用,队列

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

下面是 ES6 的实现方式,如果用 ES5 来写要在维护 this 方面多写一些代码

class _LazyMan {
  constructor(name) {
    this.tasks = [];
    const task = () => {
      console.log(`Hi! This is ${name}`);
      this.next();
    }
    this.tasks.push(task);
    setTimeout(() => {               // 把 this.next() 放到调用栈清空之后执行
      this.next();
    }, 0);
  }

  next() {
    const task = this.tasks.shift(); // 取第一个任务执行
    task && task();
  }

  sleep(time) {
    this._sleepWrapper(time, false);
    return this;                     // 链式调用
  }

  sleepFirst(time) {
    this._sleepWrapper(time, true);
    return this;
  }

  _sleepWrapper(time, first) {
    const task = () => {
      setTimeout(() => {
        console.log(`Wake up after ${time}`);
        this.next();
      }, time * 1000)
    }
    if (first) {
      this.tasks.unshift(task);     // 放到任务队列顶部
    } else {
      this.tasks.push(task);        // 放到任务队列尾部
    }
  }

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

function LazyMan(name) {
  return new _LazyMan(name);
}

下面是 ES5 的实现方式

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<title>lazyMan</title>
</head>
<body>

    <p>请打开控制台进行输入代码、调试</p>

<script type="text/javascript">

(function(window, undefined){
    var taskList = [];

    // 类
    function LazyMan(){};

    LazyMan.prototype.eat = function(str){
        subscribe("eat", str);
        return this;
    };

    LazyMan.prototype.sleep = function(num){
        subscribe("sleep", num);
        return this;
    };

    LazyMan.prototype.sleepFirst = function(num){
        subscribe("sleepFirst", num);
        return this;
    };

    // 订阅
    function subscribe(){
        var param = {},
            args = Array.prototype.slice.call(arguments);

        if(args.length < 1){
            throw new Error("subscribe 参数不能为空!");
        }

        param.msg = args[0];
        param.args = args.slice(1); // 函数的参数列表

        if(param.msg == "sleepFirst"){
            taskList.unshift(param);
        }else{
            taskList.push(param);
        }
    }

    // 发布
    function publish(){
        if(taskList.length > 0){
            run(taskList.shift());
        }
    }

    // 鸭子叫
    function run(option){
        var msg = option.msg,
            args = option.args;

        switch(msg){
            case "lazyMan": lazyMan.apply(null, args);break;
            case "eat": eat.apply(null, args);break;
            case "sleep": sleep.apply(null,args);break;
            case "sleepFirst": sleepFirst.apply(null,args);break;
            default:;
        }
    }

    // 具体方法
    function lazyMan(str){
        lazyManLog("Hi!This is "+ str +"!");

        publish();
    }

    function eat(str){
        lazyManLog("Eat "+ str +"~");
        publish();
    }

    function sleep(num){
        setTimeout(function(){
            lazyManLog("Wake up after "+ num);

            publish();
        }, num*1000);
        
    }

    function sleepFirst(num){
        setTimeout(function(){
            lazyManLog("Wake up after "+ num);

            publish();
        }, num*1000);
    }

    // 输出文字
    function lazyManLog(str){
        console.log(str);
    }

    // 暴露接口
    window.LazyMan = function(str){
        subscribe("lazyMan", str);

        setTimeout(function(){
            publish();
        }, 0);

        return new LazyMan();
    };

})(window);
</script>
</body>
</html>
最后修改:2021 年 09 月 15 日 10 : 07 AM
如果觉得我的文章对你有用,请随意赞赏