Daily-Interview-Question icon indicating copy to clipboard operation
Daily-Interview-Question copied to clipboard

第 56 题:要求设计 LazyMan 类,实现以下功能。

Open zeroone001 opened this issue 5 years ago • 138 comments

LazyMan('Tony');
// Hi I am Tony

LazyMan('Tony').sleep(10).eat('lunch');
// Hi I am Tony
// 等待了10秒...
// I am eating lunch

LazyMan('Tony').eat('lunch').sleep(10).eat('dinner');
// Hi I am Tony
// I am eating lunch
// 等待了10秒...
// I am eating diner

LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(10).eat('junk food');
// Hi I am Tony
// 等待了5秒...
// I am eating lunch
// I am eating dinner
// 等待了10秒...
// I am eating junk food

Answer

class LazyManClass {
    constructor(name) {
        this.taskList = [];
        this.name = name;
        console.log(`Hi I am ${this.name}`);
        setTimeout(() => {
            this.next();
        }, 0);
    }
    eat (name) {
        var that = this;
        var fn = (function (n) {
            return function () {
                console.log(`I am eating ${n}`)
                that.next();
            }
        })(name);
        this.taskList.push(fn);
        return this;
    }
    sleepFirst (time) {
        var that = this;
        var fn = (function (t) {
            return function () {
                setTimeout(() => {
                    console.log(`等待了${t}秒...`)
                    that.next();
                }, t * 1000);  
            }
        })(time);
        this.taskList.unshift(fn);
        return this;
    }
    sleep (time) {
        var that = this
        var fn = (function (t) {
            return function () {
                setTimeout(() => {
                    console.log(`等待了${t}秒...`)
                    that.next();
                }, t * 1000); 
            }
        })(time);
        this.taskList.push(fn);
        return this;
    }
    next () {
        var fn = this.taskList.shift();
        fn && fn();
    }
}
function LazyMan(name) {
    return new LazyManClass(name);
}
LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(4).eat('junk food');


zeroone001 avatar Apr 16 '19 23:04 zeroone001

class LazyManClass {
  constructor(name) {
    this.name = name
    this.queue = []
    console.log(`Hi I am ${name}`)
    setTimeout(() => {
      this.next()
    },0)
  }

  sleepFirst(time) {
    const fn = () => {
      setTimeout(() => {
        console.log(`等待了${time}秒...`)
        this.next()
      }, time)
    }
    this.queue.unshift(fn)
    return this
  }

  sleep(time) {
    const fn = () => {
      setTimeout(() => {
        console.log(`等待了${time}秒...`)
        this.next()
      },time)
    }
    this.queue.push(fn)
    return this
  }

  eat(food) {
    const fn = () => {
      console.log(`I am eating ${food}`)
      this.next()
    }
    this.queue.push(fn)
    return this
  }

  next() {
    const fn = this.queue.shift()
    fn && fn()
  }
}

function LazyMan(name) {
  return new LazyManClass(name)
}

lvwxx avatar Apr 17 '19 02:04 lvwxx

function LazyMan(name){
    var lazy = new Lazy(name);
    lazy.init();
    return lazy;
}
function Lazy(name){
    this.name = name;
    this.fns  = [];
    this.init = function(){
        var _this = this;
        _this.print("I am "+this.name);
        setTimeout(function(){
            _this.next();
        }, 0);
    };
    this.eat = function(food){
        var _this = this;
        _this.fns.push(function(){
            _this.print("I am eating "+food);
            _this.next();
        });
        return this;
    };
    this.sleep= function(time){
        var _this = this;
        _this.fns.push(function(){
            setTimeout(function(){
                _this.print("等待了" + time + "秒");
                _this.next();
            }, 1000*time);
        });
        return this;
    };
    this.sleepFirst = function(time){
        var _this = this;
        _this.fns.unshift(function(){
            setTimeout(function(){
                _this.print("等待了" + time + "秒");
                _this.next();
            }, 1000*time)
        });
        return this;
    };
    this.print = function(something){
        console.log(something);
    };
    this.next = function(){
        this.fns.length>0 && this.fns.shift()();
    };
}

csm0912 avatar Apr 17 '19 03:04 csm0912

function LazyMan (name) {
  class Man {
   constructor (name) {
     this._queues = []
     console.log(`Hi I am ${name}`)
     Promise.resolve().then(() => {
      this.next()
    })
    return this
   }

   _sleep = (time) => {
     return new Promise(resolve => setTimeout(resolve, time * 1000))
   }

   eat (type) {
     this._queues.push(() => {
       console.log(`I am eating ${type}`)
       this.next();
     })
     return this
   }
   sleepFirst (time) {
     this._queues.unshift(() => {
       this._sleep(time).then(() => {
         console.log(`等待了${time}秒`)
         this.next()
       })
    })
    return this
   }
   
   sleep (time) {
     this._queues.push(() => {
       this._sleep(time).then(() => {
         console.log(`等待了${time}秒`)
        this.next()
      })
     })
     return this
   }

   next () {
     const fn = this._queues.shift();
     fn && fn()
  }
 }

  return new Man(name)
}

LazyMan('Tom');

LazyMan('Tom').sleep(10).eat('lunch')

LazyMan('Tom').eat('lunch').sleep(10).eat('dinner')

LazyMan('Tom').eat('lunch').eat('dinner').sleepFirst(5).sleep(10).eat('junk food')

jefferyE avatar Apr 17 '19 03:04 jefferyE

class LazyMan {
  constructor(name) {
    this.task = [];
    this.task.push(
      () => {
        console.log(`My name is ${name}`);
        this.next();
      }
    )
    setTimeout(() => { this.next() })
  }
  eat(val) {
    this.task.push(
      () => {
        console.log(`吃 ${val}`);
        this.next();
      }
    )
    return this;
  }
  sleep(sec) {
    this.task.push(
      () => {
        setTimeout(() => {
          console.log(`睡 ${sec} 秒`);
          this.next();
        }, sec * 1000);
      }
    )
    return this;
  }
  next() {
    let fn = this.task.shift();
    fn && fn();
  }
}

let lazyCzh = new LazyMan('czh');
lazyCzh.eat('apple').eat('banana').sleep(3).eat('orange');

Yanhua67 avatar Apr 17 '19 03:04 Yanhua67

Proxy 版本

function LazyMan(username) {
  console.log(' Hi I am ' + username);

  var temp = {
    taskList: [],
    sleepFirst(timeout) {
      return () => {
        setTimeout(() => {
          console.log(`等待了${timeout}秒...`);
          this.next();
        }, timeout * 1000);
      };
    },
    sleep(timeout) {
      return () => {
        setTimeout(() => {
          console.log(`等待了${timeout}秒...`);
          this.next();
        }, timeout * 1000);
      };
    },
    eat(type) {
      return () => {
        console.log(`I am eating ${type}`);
        this.next();
      };
    },
    next() {
      var fn = this.taskList.shift();
      fn && fn();
    }
  };

  var proxy = new Proxy(temp, {
    get(target, key, receiver) {
      return function(...rest) {
        if (key === 'sleepFirst') {
          target.taskList.unshift(target[key](rest));
        } else {
          target.taskList.push(target[key](rest));
        }
        return receiver;
      };
    }
  });

  setTimeout(() => {
    temp.next();
  }, 0);
  return proxy;
}
LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(10).eat('junk food');
// Hi I am Tony
// 等待了5秒...
// I am eating lunch
// I am eating dinner
// 等待了10秒...
// I am eating junk food

mengsixing avatar Apr 17 '19 03:04 mengsixing

    function LazyMan(name) {
      console.log("Hi I am Tony");
      return {
        sleepTime: 0,
        firstSleepTime: 0,
        sleep: function(second) {
          let time = 0;
          function logText() {
            setTimeout(() => {
              console.log("等待了十秒...");
            }, time);
          }

          setTimeout(() => {
            time = second * 1000 + this.firstSleepTime * 1000;
            logText();
          }, 0);

          this.sleepTime = this.sleepTime + second;
          return this;
        },
        eat: function(meal) {
          let time = this.sleepTime * 1000;

          function logText() {
            setTimeout(() => {
              console.log("I am eating " + meal);
            }, time);
          }
          setTimeout(() => {
            time = time + this.firstSleepTime * 1000;
            logText();
          }, 0);
          return this;
        },

        sleepFirst: function(second) {
          let time = second * 1000;
          setTimeout(() => {
            console.log("等待了5秒");
          }, time);
          this.firstSleepTime = second;
          return this;
        }
      };
    };

happywanghao avatar Apr 17 '19 03:04 happywanghao

写个链表实现

class Node {
  constructor(func = null) {
    this.func = func;
    this.next = null;
  }

  async exec() {
    if (this.func) {
      await this.func();
    }
    if (this.next && this.next.func) {
      this.next.exec();
    }
  }
}

function delayFunc(delay) {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log(`等待了${delay}秒...`);
      resolve();
    }, delay * 1000);
  });
}

class Lazy {
  constructor(name) {
    this.name = name;
    this.head = new Node();
    this.current = this.head;
    Promise.resolve().then(() => this.head.exec());
  }

  eat(sth) {
    const log = () => {
      console.log("I am eating " + sth);
    };
    this.current.next = new Node(log);
    this.current = this.current.next;
    return this;
  }

  sleep(delay) {
    this.current.next = new Node(() => delayFunc(delay));
    this.current = this.current.next;
    return this;
  }

  sleepFirst(delay) {
    let head = new Node(() => delayFunc(delay));
    if (!this.head.func) {
      head.next = this.head.next;
    } else {
      head.next = this.head;
    }
    this.head = head;
    return this;
  }
}

function LazyMan(name) {
  console.log("I am " + name);
  return new Lazy(name);
}

LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(10).eat('junk food');

BaconZhang avatar Apr 17 '19 05:04 BaconZhang

function LazyMan(name){
 return new class LazyMan{
  constructor(name){
   this.tasks=[]
   this.hello(name)
   setTimeout(this.next.bind(this),0)
  }
  log(str){console.log(str);return true}
  next(){
   var fn=this.tasks.shift()
   fn&&fn.apply(this)
  }
  hello(name){
   this.tasks.push(()=>this.log('hello '+name)&&this.next())
   return this
  }
  sleepfirst(time){
   this.tasks.unshift(()=>this.log('sleep '+time)&&setTimeout(this.next.bind(this),time))
   return this
  }
  eat(what){
   this.tasks.push(()=>this.log('eat '+what)&&this.next())
   return this
  }
  sleep(time){
   this.tasks.push(()=>this.log('sleep '+time)&&setTimeout(this.next.bind(this),time))
   return this
  }
 }(name)
}

Seasonley avatar Apr 17 '19 05:04 Seasonley

/**
 * 普通 eat方法, 存放在立即执行队列中, 用settimeout来执行
 * sleep 方法  每次调用这个方法, 都单独开一个定时器, 把新的任务加入到这个队列
 * sleepFirst方法 把立即执行的任务队列的任务 塞到新的定时器任务队列
 */

class LazymanClass {
  constructor (_name = '') {
    this._immediateTask = []
    this._immediateTimer = null
    this._sleepTaskMap = {}
    this._curSleepTaskKey = null
    this._log(`Hi i am ${_name}`)
  }

  eat (meal) {
    // 添加新任务之前 清空之前的 立即定时器
    this._immediateTimer && clearTimeout(this._immediateTimer)

    const _eat = (meal) => {
      this._log(`i am eating ${meal}`)
    }

    if (this._curSleepTaskKey === null) {
      this._immediateTask.push(_eat.bind(this, meal))
    } else {
      this._sleepTaskMap[this._curSleepTaskKey].push(_eat.bind(this, meal))
    }

    this._immediateTimer = setTimeout(() => {
      this._runImmeadiateTask()
    })
    return this
  }

  sleep (second) {
    const key = Math.random()
    this._curSleepTaskKey = key
    this._sleepTaskMap[this._curSleepTaskKey] = []
    setTimeout(() => {
      this._log(`等待了${second}秒`);
      this._runSleepTask(key)
    }, second * 1000)
    return this
  }

  sleepFirst (second) {
    const key = Math.random()
    this._curSleepTaskKey = key
    this._sleepTaskMap[key] = []
    this._immediateTask.map(task => {
      this._sleepTaskMap[key].push(task)
    })
    this._immediateTask = []

    setTimeout(() => {
      this._log(`等待了${second}秒`);
      this._runSleepTask(key)
    }, second * 1000)
    return this
  }

  _runImmeadiateTask () {
    this._immediateTask.map(task => {
      typeof task === 'function' && task()
    })
    this._immediateTask = []
  }

  _runSleepTask (key) {
    this._sleepTaskMap[key].map(task => {
      typeof task === 'function' && task()
    })
    this._sleepTaskMap[key] = []
  }

  _log(str) {
    console.log(str)
  }
}

function LazyMan(name) {
  return new LazymanClass(name)
}

const test = () => {
  // LazyMan('Tony')

  // LazyMan('Tony').eat('lunch')

  // LazyMan('Tony').sleep(2).eat('lunch')

  // LazyMan('Tony').eat('lunch').sleep(2).eat('diner')
  
  LazyMan('Tony').eat('lunch').eat('diner').sleepFirst(1).sleep(2).eat('junk food')
}

test()

lulusir avatar Apr 17 '19 06:04 lulusir


class LazyManClass {
    constructor(props){
        this.sub = []
        console.log(`Hi I am ${props}`)
        setTimeout(()=>{
            this.start()
        },0)
    }
    eat (params){
        this.sub.push(function(){
            console.log(`I am eating ${params}`)
        })
        return this
    }
    sleepFirst(s){
        this.sub.unshift(this.delay(s))
        // 这边还没有返回  同步就继续执行了
       return this
    }
    delay(s) {
        return () => {
            return new Promise(resolve => {
                setTimeout(function () {
                    console.log(`等待了${s}秒...`)
                    resolve()
                },s * 1000)
            })
        }
    }
    sleep (s){
        this.sub.push(this.delay(s))
        // 这边还没有返回  同步就继续执行了
       return this
    }
    async start(){
        for (const iterator of this.sub) {
            await iterator()
        }
    }
}
function LazyMan(props) {
    return  new LazyManClass(props)
}
LazyMan('Tony').eat('lunch').eat('diner').sleepFirst(1).sleep(2).eat('junk food')
// Hi I am Tony
// 等待了5秒...
// I am eating lunch
// I am eating dinner
// 等待了10秒...
// I am eating junk food

Banlangenn avatar Apr 17 '19 07:04 Banlangenn

function LazyMan(name) {
    if (!(this instanceof LazyMan)) {
        return new LazyMan(name);
    }
    this.name = name;
    this.delayTime = 0;
    this.tasks = [];
    console.log(`Hi I am ${this.name}`);
    this._ready();
}

LazyMan.prototype._ready = function () {
    setTimeout(() => {
        setTimeout(() => {
            console.log(`等待了${this.delayTime}秒...`);
            this._doTasks();
        }, this.delayTime * 1000);
    }, 0);
}

LazyMan.prototype._doTasks = function () {
    const tasks = this.tasks;
    if (tasks.length === 0) return;
    const {delayTime, callback} = tasks[0];
    setTimeout(() => {
        callback && callback();
        tasks.shift();
        this._doTasks();
    }, delayTime);
}

LazyMan.prototype.eat = function (foods) {
    this.tasks.push({
        delayTime: 0,
        callback() {
            console.log(`I am eating ${foods}`);
        },
    });
    return this;
}

LazyMan.prototype.sleep = function (seconds) {
    if (seconds >= 0) {
        this.tasks.push({
            delayTime: seconds * 1000,
            callback() {
                console.log(`等待了${seconds}秒...`)
            }
        });
    }
    return this;
}

LazyMan.prototype.sleepFirst = function (seconds) {
    if (seconds > 0) {
        this.delayTime = seconds;
    }
    return this;
}

yiqingfeng avatar Apr 17 '19 08:04 yiqingfeng

function LazyMan(name) {
  if (this instanceof LazyMan) {
    this.task = [];
    this.log('Hi I am '+ name);
    setTimeout(() => {
      this.next();
    }, 0);
  }
  return (this instanceof LazyMan) && this || new LazyMan(name);
}

LazyMan.prototype.log = console.log;

LazyMan.prototype.next = function() {
  const [fn, ...tail] = this.task;
  fn && (this.task = tail) && fn();
}

LazyMan.prototype.eat = function(food) {
  this.task = [
    ...this.task,
    () => {
      this.log('I am eating '+ food);
      this.next();
    }
  ]
  return this;
}

LazyMan.prototype.sleep = function(timeout) {
  this.task = [
    ...this.task,
    () => {
      setTimeout(() => {
        this.next();
      }, timeout * 1000);
    }
  ]
  return this;
}

LazyMan.prototype.sleepFirst = function(timeout) {
  this.task = [
    () => {
      setTimeout(() => {
        this.next();
      }, timeout * 1000)
    },
    ...this.task
  ]
  return this;
}


LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(1).sleep(2).eat('junk food');

Mistyyyy avatar Apr 17 '19 08:04 Mistyyyy

// 写一个 setTimeout 就可以了。

class lazyManClass {
    constructor(name){
        this.taskList = []
        this.init(name)
    }

    init(name){
        var _this = this
        this.taskList.push({
            time: 0, // 是否是异步
            fn:(function(s){ // 函数自执行
                    return function() {
                        _this.exec()
                        console.log('Hi I am ', s)
                    }
                })(name)
        })
        this.exec()
        return this
    }
    eat(str) {
        var _this = this
        this.taskList.push({
            time: 0,
            fn: (function(s){
                    return function() {
                        _this.exec()
                        console.log('I am eating ', s)
                    }
                })(str)
        })
        
        return this
    }
    sleep(t){
        var _this = this
        this.taskList.push({
            time: t * 1000,
            fn: (function(time){
                    return function() {
                        _this.exec()
                        console.log(`等待了${time}秒...`) 
                    }
                })(t)
        })
        return this
    }
    sleepFirst(t) {
        var _this = this
        this.taskList.unshift({
            time: t * 1000,
            fn: (function(time){
                    return function() {
                        _this.exec()
                        console.log(`等待了${time}秒...`) 
                    }
                })(t)
        })
        return this
    }
    exec(){
        var obj = this.taskList.shift()
        if(!obj) {
            return   // 最后一个fn里面,也会执行 _this.exec(),这个时候taskList已经空了
        }
        setTimeout(() => {
            obj.fn && obj.fn.call(this)
        }, obj.time || 0)
        
    }
}

function LazyMan(name) {
    return new lazyManClass(name)
}   

zhuzhh avatar Apr 17 '19 11:04 zhuzhh

class LazyMan {
	constructor (user) {
		this.timeList = [];
		console.log(`Hi I am ${user}`)
		Promise.resolve().then(res => this.next());
	}
	eat (res) {
		var fn =  () => {
			console.log(`I am eating ${res}`);
			this.next();
		}
		this.timeList.push(fn);
		return this;
	}
	sleep (time) {
		var fn = res => {
			setTimeout(res => {
				console.log(`等待了${time}秒`);
				this.next();
			},time*1000)
		}
		this.timeList.push(fn);
		return this;
	}
	next () {
		var fn = this.timeList.shift();
		fn && fn();
	}
	sleepFrist (time) {
		var fn = res => {
			setTimeout(res => {
				console.log(`先等待了${time}秒`);
				this.next();
			},time*1000)
		}
		this.timeList.unshift(fn);
		return this;
	}
}
function lazyman (res) {
	return new LazyMan(res)
}
_//lazyman('静静').sleep(2).eat('饺子').sleep(3).eat('面').sleepFrist(1).eat('others')
//Hi I am 静静
//先等待了1秒
//等待了2秒
//I am eating 饺子
//等待了3秒
//I am eating 面
//I am eating others_

neofanfei avatar Apr 17 '19 11:04 neofanfei

class LazyMan {
    constructor(name) {
        this.tasks = []
        const task = () => {
            console.log(name)
        }
        this.tasks.push(task)
        setTimeout(() => {
            this.exec()
        })
    }

    sleep(time) {
        const task = () => new Promise(resolve => {
            setTimeout(resolve, time)
        })
        this.tasks.push(task)
        return this
    }
    sleepFirst(time) {
        const task = () => new Promise(resolve => {
            setTimeout(resolve, time)
        })
        let originTask = this.tasks.shift()
        this.tasks.unshift(originTask,task)
        return this
    }
    eat(food) {
        const task = () => {
            console.log(food)
        }
        this.tasks.push(task)
        return this
    }

     async exec() {
        for (let task of this.tasks) {
            await task()
        }
    }
}

yeyan1996 avatar Apr 18 '19 07:04 yeyan1996

    function LazyManClass(name){
        this.name = name;
        console.log('Hi I am '+name);
        //存储行为列表
        this.taskList = [];

        //声明类行为执行函数
        this.doTask = function(){
            var fn = this.taskList.shift();
            if(fn){
                fn();
            }
        };
        
        //异步执行默认行为函数
        var _this = this;
        setTimeout(function(){
            _this.doTask();
        },0);
        
    }
        

    LazyManClass.prototype.eat = function(food){
        var _this = this;
        var fn = function(){
            console.log('I am eating '+food);
            _this.doTask();
        }

        //维护行为列表
        this.taskList.push(fn);
        return this;
    }

    LazyManClass.prototype.sleepFirst = function(time){
        var _this = this;
        var fn = function(){
            setTimeout(function(){
                console.log('等待了 '+time+'秒...');
                _this.doTask();
            },time*1000)
        }
        
        //维护行为列表
        this.taskList.unshift(fn);
        return this;
    }

    LazyManClass.prototype.sleep = function(time){
        var _this = this;
        var fn = function(){
            setTimeout(function(){
                console.log('等待了 '+time+'秒...');
                _this.doTask();
            },time*1000)
        }

        //维护行为列表
        this.taskList.push(fn);
        return this;
    }

    //函数调用返回实例化对象
    function LazyMan(name){
        return new LazyManClass(name);
    }
    LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(10).eat('junk food');
   //感谢各位前辈们的代码思路,自己用es5写了一遍

jayPiece avatar Apr 18 '19 08:04 jayPiece

有大佬能解答下next()调用的时机吗,这个运行流程我有点看不懂=。=

twosugar avatar Apr 19 '19 07:04 twosugar

有大佬能解答下next()调用的时机吗,这个运行流程我有点看不懂=。=

我不是大佬,但我理解的next()应该是在LazyMan('Toney')的时候异步执行的,因为异步,所以它还没干活的时候,链式调用早结束了,taskList也把要干的活按照规则存好了,随后它开始干活,由于taskList中每个活函数执行完后又主动调用了一次next(),所以能一直把taskList中的活干完

jayPiece avatar Apr 19 '19 07:04 jayPiece

有大佬能解答下next()调用的时机吗,这个运行流程我有点看不懂=。=

我不是大佬,但我理解的next()应该是在LazyMan('Toney')的时候异步执行的,因为异步,所以它还没干活的时候,链式调用早结束了,taskList也把要干的活按照规则存好了,随后它开始干活,由于taskList中每个活函数执行完后又主动调用了一次next(),所以能一直把taskList中的活干完

如果真是这样那就好理解了,谢谢解答!!

twosugar avatar Apr 19 '19 07:04 twosugar

function LazyMan(name) {
    console.log(`I am ${name}`);
    var task = [];
    function execute() {
	var fn = task.shift();
        fn && fn();	
    }
   // delay execute
    setTimeout(function() {
        execute();
    }, 0);
    function _sleep(n = 0) {
        console.log(`${name} is sleeping ${n}`);
        setTimeout(function() {
            execute();
        }, n * 1000);
    }
    function _eat(food) {
        console.log(`${name} is eating ${food}`);
        execute();
    }
    var obj = {
	sleep: function() {
	    task.push(_sleep.bind(null, ...arguments));
	    return obj;
        },
	eat: function() {
	    task.push(_eat.bind(null, ...arguments));
	    return obj;
	},
        sleepFirst: function() {
	    task.unshift(_sleep.bind(null, ...arguments));
	    return obj;
	}
    };
    return obj;
}
LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(10).eat('junk food');

RichardPear avatar Apr 20 '19 07:04 RichardPear

有大佬能解答下next()调用的时机吗,这个运行流程我有点看不懂=。=

我不是大佬,但我理解的next()应该是在LazyMan('Toney')的时候异步执行的,因为异步,所以它还没干活的时候,链式调用早结束了,taskList也把要干的活按照规则存好了,随后它开始干活,由于taskList中每个活函数执行完后又主动调用了一次next(),所以能一直把taskList中的活干完

如果真是这样那就好理解了,谢谢解答!!

在constructor中, next()方法执行在 setTimeout 中,setTimeout 是一个task,当 js 运行到 setTimeout 的时候,会把他放到 task 任务队列中,等到所有的同步的任务执行完后,就会执行setTimeout 中的this.next()方法 , 这个问题的关键问题是 js 的事件队列问题 。 你可以参考这个链接详细了解 https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/7?from=groupmessage&isappinstalled=0

lzbSun avatar Apr 22 '19 02:04 lzbSun

@GuidingStarKe

lzbSun avatar Apr 22 '19 02:04 lzbSun

有大佬能解答下next()调用的时机吗,这个运行流程我有点看不懂=。=

我不是大佬,但我理解的next()应该是在LazyMan('Toney')的时候异步执行的,因为异步,所以它还没干活的时候,链式调用早结束了,taskList也把要干的活按照规则存好了,随后它开始干活,由于taskList中每个活函数执行完后又主动调用了一次next(),所以能一直把taskList中的活干完

如果真是这样那就好理解了,谢谢解答!!

在constructor中, next()方法执行在 setTimeout 中,setTimeout 是一个task,当 js 运行到 setTimeout 的时候,会把他放到 task 任务队列中,等到所有的同步的任务执行完后,就会执行setTimeout 中的this.next()方法 , 这个问题的关键问题是 js 的_事件队列问题_ 。 你可以参考这个链接详细了解 https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/7?from=groupmessage&isappinstalled=0

首先谢谢解答和分享!

twosugar avatar Apr 22 '19 03:04 twosugar

class LazyMan {
  constructor(name){
    this.name = name
    this.eventQueue = []
    console.log('Hi , I am %s.', name )
    setTimeout(()=>{
      this.drain()
    },0)
  }
  eat(meal){
    const fn = function _eat(next){
      console.log('I am eating %s.',meal)
      next && next()
    }
    this.eventQueue.push(fn)
    return this
  }
  sleep(second){
    const fn = function _sleep(next){
      console.log('I am waiting %d second.', second)
      setTimeout(()=>{
        next && next()
      },second*1000)
    }
    this.eventQueue.push(fn)
    return this
  }
  sleepFirst(second){
    const fn = function _sleepFirst(next){
      console.log('I am waiting %d second.', second)
      setTimeout(()=>{
        next && next()
      },second*1000)
    }
    this.eventQueue.splice(0,0,fn)
    return this
  }
  drain(){
    const fnComposed = this.eventQueue.reduceRight(function _reduceRight(pre,next){
      return function (){
        return next(pre)
      }
    },)
    fnComposed()
  }
}
const TonyStark =new LazyMan('Tony').eat('lunch').sleep(10).eat('dinner');

bohaixv avatar Apr 24 '19 03:04 bohaixv

用了async,不需callback, 下面是两种方法放一起了。 第一种方法注释掉了,调用任务eat或者sleep或者sleepFirst时,把任务的data存放队列里,在init的方法里异步调用async executeTasks, 任务存放是同步的,先于异步的方法executeTasks执行完,在executeTasks方法里依次让任务data出列,然后执行相应的任务。

第二种是,使用next方法,每个任务最后都会调用一次next方法,把每个任务都压入队列,next的一次调用也是异步的,晚于同步的任务入列执行,next方法里让当前的任务入列,并执行。

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

class LazyManClass {
    constructor(name) {
        this.taskList = [];
        // used for method executeTasks
        // this.taskDataList = [];
        this.init(name);
    }

    init(name) {
        this.printLog('name', name);
        setTimeout(() => {
            // the alternative solution
            //this.executeTasks();
            this.next();
        }, 0);
    }

    printLog(type, data) {
        const LOG_MAP = {
            'name': `Hi, I am ${data}`,
            'eat': `I am eating ${data}.`,
            'sleep': `Waited for ${data} seconds.`,
            'error': `Got something wrrong: ${data}.`
        };
        console.log(LOG_MAP[type]);
    }

    delayPromise(t) {
        return new Promise(resolve => {
            setTimeout(() => {
                resolve();
            }, t * 1000);
        });
    };

    createTaskData(type, data) {
        return { type, data };
    }

    createTask(type, data) {
        return async () => {
            if (type === 'sleep') {
                try {
                    await this.delayPromise(data);
                }
                catch(e) {
                    this.printLog('error', e);
                }
            }
            this.printLog(type, data);
            this.next();
        }
    }

    addTask(type, data, isFirst=false) {
        if (isFirst) {
            // used for method executeTasks
            // this.taskList.unshift(this.createTask(type, data));
            this.taskList.unshift(this.createTask(type, data));
        } else {
            // used for method executeTasks
            // this.taskList.unshift(this.createTask(type, data));
            this.taskList.push(this.createTask(type, data));
        }
    }

    eat(str) {
        this.addTask('eat', str);
        return this;
    }

    sleep(t) {
        this.addTask('sleep', t);
        return this;
    }

    sleepFirst(t) {
        this.addTask('sleep', t, true);
        return this;
    }

    next() {
        if (this.taskList.length > 0) {
            let task = this.taskList.shift();
            task && task();
        }
    }
    async executeTasks() {
        let taskDataList = this.taskDataList;
        while (taskDataList.length > 0) {
            let { type, data } = taskDataList.shift();
            if (type === 'sleep') {
                try {
                    await this.delayPromise(data);
                }
                catch(e) {
                    this.printLog('error', e);
                }
            }
            this.printLog(type, data);
        }
    }
}

pengcc avatar Apr 26 '19 14:04 pengcc

image

有没有大佬解答一下,这里传立即执行函数的返回值(函数)和直接传红字部分的函数,有什么区别吗

kangkai124 avatar Apr 29 '19 10:04 kangkai124

var fn = (n) => { console.log(n) }

你这样写,n的找不到name 你这样写,fn是个函数,而fn执行的时候是在next方法里执行的。而fn需要的的参数,你怎么获取到name呢?

在 2019-04-29 18:25:18,"kk" [email protected] 写道:

有没有大佬解答一下,这里传立即执行函数的返回值(函数)和直接传红字部分的函数,有什么区别吗

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or mute the thread.

zhuzhh avatar Apr 30 '19 05:04 zhuzhh

image

有没有大佬解答一下,这里传立即执行函数的返回值(函数)和直接传红字部分的函数,有什么区别吗

立即执行函数的作用是在内部函数还没有执行的时候就已经为内部函数绑定好了对应参数的值,如果不用立即函数的话也可以用bind方法

var name = '小明'
var fn = function (n){
 console.log(`I am eating ${n}`)
 this.next()
}.bind(null, name)

上面的代码实际上是让fn等于下面这个函数:
function (){
 console.log(`I am eating 小明`)
 this.next()
}

这样一来无论你在什么地方执行fn都不需要传参数了,直接fn()不用参数也能达到和普通fn的fn(name )效果一样了

YagamiNewLight avatar May 06 '19 19:05 YagamiNewLight

不用类的实现,js里基本用类实现的用对象也可以实现。

LazyMan('Tony')
// Hi I am Tony

LazyMan('Tony')
  .sleep(10)
  .eat('lunch')
// Hi I am Tony
// 等待了10秒...
// I am eating lunch

LazyMan('Tony')
  .eat('lunch')
  .sleep(10)
  .eat('dinner')
// Hi I am Tony
// I am eating lunch
// 等待了10秒...
// I am eating diner

LazyMan('Tony')
  .eat('lunch')
  .eat('dinner')
  .sleepFirst(5)
  .sleep(10)
  .eat('junk food')
// Hi I am Tony
// 等待了5秒...
// I am eating lunch
// I am eating dinner
// 等待了10秒...
// I am eating junk food

下面是实现

let man = {
  queue: []
}

function LazyMan(name) {
  console.log(`Hi I am ${name}`)
  setTimeout(() => {
    man.next()
  }, 0)
  return man
}

man.eat = food => {
  man.queue.push(() => {
    console.log(`I am eating ${food}`)
    man.next()
  })
  return man
}

man.sleep = timeout => {
  man.queue.push(() => {
    setTimeout(() => {
      console.log(`等待了${timeout}秒`)
      man.next()
    }, timeout * 1000)
  })
  return man
}

man.sleepFirst = timeout => {
  man.queue.unshift(() => {
    setTimeout(() => {
      console.log(`等待了${timeout}秒`)
      man.next()
    }, timeout * 1000)
  })
  return man
}

man.next = () => {
  if (man.queue.length > 0) {
    man.queue.shift()()
  }
}

liujuntao123 avatar May 30 '19 08:05 liujuntao123

const LazyMan = name => new class Cp {
            constructor(name) {
                this.name = name;
                this._queues = []
                console.log(` Hi I am ${name}`)
                Promise.resolve().then(() => {
                    this.next()
                })
                // return this
            }
            static _sleep = time => new Promise(resolve => setTimeout(resolve, time * 1000))
            eat(ft) {
                this._queues.push(() => {
                    console.log(`I am eating ${ft}`)
                    this.next()
                })
                return this
            }
            sleepFirst(time) {
                this._queues.unshift(async () => {
                    await Cp._sleep(time)
                    console.log(`等待了 ${time} 秒`)
                    this.next()
                })
                return this
            }
            sleep(time) {
                this._queues.push(async () => {
                    await Cp._sleep(time)
                    console.log(`等待了 ${time} 秒`)
                    this.next()
                })
                return this
            }
            next() {
                const fn = this._queues.shift();
                fn && fn()
            }
        }(name)
    
    LazyMan('Tom');

    LazyMan('Tom').sleep(10).eat('lunch')

    LazyMan('Tom').eat('lunch').sleep(3).eat('dinner')

    LazyMan('Tom').eat('lunch').eat('dinner').sleepFirst(5).sleep(10).eat('junk food')

dguoqing avatar Jul 10 '19 08:07 dguoqing

class LazyMan {
  constructor(name) {
    this.promise = Promise.resolve().then(() => console.log(`Hi I am ${name}`))
  }
  sleepFirst(time) {
    this.promise = this.promise.then(() => new Promise(resolve => setTimeout(resolve, time * 1000)))
    return this
  }
  eat(name) {
    setTimeout(() => {
      this.promise = this.promise.then(() => console.log(`I am eating ${name}`))
    }, 0)
    return this
  }
  sleep(time) {
    setTimeout(() => {
      this.promise = this.promise.then(() => new Promise(resolve => setTimeout(resolve, time * 1000)))
    }, 0)
    return this
  }
}

不知道符不符合要求

logan70 avatar Jul 10 '19 11:07 logan70

class LazyManClass {
  constructor (username) {
    this.username = username
    this.taskList = []
    this._hello()
  }

  _addTask (task, data) {
    clearTimeout(this.timer)
    this.taskList.push(() => {
      this[task](data)
    })
    this.timer = setTimeout(() => {
      this._runTask()
    })

    return this
  }

  _runTask () {
    for (let i = 0; i < this.taskList.length; i++) {
      this.taskList[i]()
    }
  }

  _insertTask (task, data, index) {
    clearTimeout(this.timer)
    this.taskList.splice(index, 0, () => {
      this[task](data)
    })
    this.timer = setTimeout(() => {
      this._runTask()
    })
    return this
  }

  registerBehave (name, action) {
    this['_' + name] = action
    this[name] = (data) => {
      const fnName = '_' + name
      if (/\w+First/.test(fnName)) {
        this._insertTask(fnName, data, 0)
      } else {
        this._addTask(fnName, data)
      }
      return this
    }
    return this
  }
  _hello () {
    console.log('Hi I am ' + this.username)
  }
}

function LazyMan (name) {
  const man = new LazyMan(name)
  return man
    .registerBehave('sleep', function (time) {
      console.log('等待了 ' + time + ' 秒种...')
    })
    .registerBehave('eat', function (mealName) {
      console.log('I am eating ' + mealName)
    })
    .registerBehave('sleepFirst', function (time) {
      console.log('等待了 ' + time + ' 秒种...')
    })
}

LazyMan('Pikachu').eat('lunch').sleep(10).sleepFirst(8)

有点长…… 但是这样行为就是可以注册的了,以后想加个 gamingFirst 之类的都可以。

DannySu09 avatar Jul 11 '19 15:07 DannySu09

用Generator做~

function LazyMan(str = "") {
  return new (class {
    list = [];
    task;
    constructor(str) {
      this.list.push(`Hi I am ${str}`);
      this.task = this.log();
      setTimeout(() => this.task.next());
    }
    sleepFirst = t => {
      this.list.splice(1, 0, t);
      return this;
    };
    sleep = t => {
      this.list.push(t);
      return this;
    };
    eat = str => {
      this.list.push(`I am eating ${str}`);
      return this;
    };

    log = function*() {
      for (const val of this.list) {
        yield (() => {
          if (typeof val !== "number") console.log(val);
          setTimeout(() => this.task.next(), (val >> 0) * 1000);
        })();
      }
    };
  })(str);
}

LazyMan("Tony")
  .eat("lunch")
  .eat("dinner")
  .sleepFirst(5)
  .sleep(10)
  .eat("junk food");

shaokr avatar Jul 12 '19 03:07 shaokr

class ArrayInherit extends Array {
  constructor(options) {
      super(options);
      this.options=options;
  }

  push(item) {
    super.push(item);
    this.options.pushCb(item)
  }
}

class LazyMan {
  constructor(name) {
    this.name = name;
    this.sleepQueue = new ArrayInherit({pushCb: function(item) {
      setTimeout(() => {
        item.cb();
      }, item.sleepWait)
    }});

    this.queueCb = [];
    this.sleepWaitTemp = 0;

    console.log(`Hi I am ${this.name}`);
  }

  sleep(sleepWait) {
    this.sleepWaitTemp = sleepWait;

    return this;
  }

  sleepFirst(sleepFirstWait) {
    const queueCbTemp = this.queueCb;

    this.queueCb = []

    setTimeout(() => {
      queueCbTemp.forEach(cb => {
        cb();
      })

    }, sleepFirstWait)

    return this;
  }

  get hasSleeped() {
    return this.sleepWaitTemp > 0;
  }

  eat(thing) {
    function cb() {
      console.log(`I am eating ${thing}`);
    }
    
    if (this.hasSleeped) {
      this.queueCb.forEach(cb => {
        cb();
      })

      this.queueCb = []

      this.sleepQueue.push({
        sleepWait: this.sleepWaitTemp,
        cb: cb.bind(this, thing)
      });
    } else {
      this.queueCb.push(cb.bind(this, thing))
    }

    return this;
  }
}

var a = new LazyMan('Tom');
a.sleep(1000).eat('lunch');

var a = new LazyMan('Tom');
a.eat('lunch').sleep(1000).eat('dinner');

var a = new LazyMan('Tom');
a.eat('lunch').eat('dinner').sleepFirst(2000).sleep(5000).eat('junk food')

negativeentropy9 avatar Jul 12 '19 08:07 negativeentropy9

其实题目主要考虑的点有以下几个方面:

  1. 链式调用 -> return this
  2. 链式调用终止判断 -> 我用了setTimeout会在被主线程pendding的方式,楼上的很多方案其实更好
  3. 依次执行一个异步数组 -> 同样楼上很多Promise的嵌套方案就很好,我是采用了递归,最后一次性执行
function LazyMan (name) {
  console.log('Hi I am Tony')
  return {
    loops: [],
    tick: null,
    eat (something) {
      this.wait()
      this.loops.push(() => new Promise(resolve => {
        resolve(true)
        console.log('I am eating ' + something)
      }))
      return this
    },
    sleep (time) {
      this.wait()
      this.loops.push(() => new Promise(resolve => {
        setTimeout(() => {
          console.log(`等待了${time}秒...`)
          resolve(true)
        }, time * 1000)
      }))
      return this
    },
    sleepFirst (time) {
      this.wait()
      this.loops.unshift(() => new Promise(resolve => {
        setTimeout(() => {
          console.log(`等待了${time}秒...`)
          resolve(true)
        }, time * 1000)
      }))
      return this
    },
    wait () {
      clearTimeout(this.tick)
      this.tick = setTimeout(() => {
        this.done()
      })
    },
    done () { // 处理所有的操作
      if (this.loops.length > 0) {
        this.loops.shift()().then(() => {
          this.done()
        })
      }
    },
  }
}

PatrickLh avatar Jul 13 '19 01:07 PatrickLh

function LazyMan (name) { let obj = Object.create(LazyMan.prototype); obj.name = name; obj.taskList = []; console.log(Hi I am ${name}); obj.next(); return obj; }

LazyMan.prototype.eat = function (message) { this.taskList.push({ type: 'eat', payload: message }); return this; };

LazyMan.prototype.sleep = function (time) { this.taskList.push({ type: 'sleep', payload: time }); return this; };

LazyMan.prototype.sleepFirst = function (time) { this.taskList.unshift({ type: 'sleep', payload: time }); return this; };

LazyMan.prototype.next = function () { const self = this; setTimeout(async function () { let task = null; while (task = self.taskList.shift()) { switch (task.type) { case 'sleep': { await new Promise((resolve) => setTimeout(resolve, task.payload * 1000)); console.log(等待了${task.payload}秒); break; } case 'eat': { console.log(I am eating ${task.payload}); break; } } } }, 0); }

young122849 avatar Jul 13 '19 14:07 young122849

class LazyManClass {
  constructor(name) {
    this.taskList = []
    this.name = name
    console.log(`Hi I am ${name}`)
    setTimeout(() => {
      this.next()
    }, 0)
  }
  eat (name) {
    this.taskList.push(() => {
      console.log(`I am eating ${name}`)
      this.next()
    })
    return this
  }
  sleep (delay) {
    this.taskList.push(() => {
      setTimeout(() => {
        console.log(`等待了${delay}秒...`)
        this.next()
      }, delay * 1000)
    })
    return this
  }
  sleepFirst (delay) {
    this.taskList.unshift(() => {
      setTimeout(() => {
        console.log(`等待了${delay}秒...`)
        this.next()
      }, delay * 1000)
    })
    return this
  }
  next () {
    const fn = this.taskList.shift()
    fn && fn()
  }
}

function LazyMan(name) {
  return new LazyManClass(name)
}

LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(10).eat('junk food')

yujihu avatar Jul 14 '19 09:07 yujihu

执行Promise队列

class Lazy {
    constructor(name) {
        console.log(`Hi I am ${name}`);
        this.task = [];
        setTimeout(() => {
            this.execQueue(0);
        }, 0);
    }
    execQueue(index) {
        var that = this;
        if (that.task.length && index < that.task.length) {
            that.task[index]().then(res => {
                if (res) {
                    that.execQueue(++index);
                }
            })
        }
    }
    sleep(s) {
        this.task.push(() => {
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    console.log(`等待了${s}秒...`)
                    resolve(true)
                }, s * 1000);
            })
        })
        return this;
    }
    sleepFirst(s) {
        this.task.unshift(() => {
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    console.log(`等待了${s}秒...`)
                    resolve(true)
                }, s * 1000);
            })
        })
        return this;
    }
    eat(str) {
        this.task.push(() => {
            return new Promise((resolve, reject) => {
                console.log(`I am eating ${str}`);
                resolve(true);
            });
        })
        return this;
    }
}
function LazyMan(name) {
    return new Lazy(name);
}
// LazyMan('Tony').sleep(10).eat('lunch');
// LazyMan('Tony').eat('lunch').sleep(10).eat('dinner');
// LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(10).eat('junk food');

richard1015 avatar Jul 15 '19 03:07 richard1015

LazyMan('Tony');
// Hi I am Tony

LazyMan('Tony').sleep(10).eat('lunch');
// Hi I am Tony
// 等待了10秒...
// I am eating lunch

LazyMan('Tony').eat('lunch').sleep(10).eat('dinner');
// Hi I am Tony
// I am eating lunch
// 等待了10秒...
// I am eating diner

LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(10).eat('junk food');
// Hi I am Tony
// 等待了5秒...
// I am eating lunch
// I am eating dinner
// 等待了10秒...
// I am eating junk food

Answer

class LazyManClass {
    constructor(name) {
        this.taskList = [];
        this.name = name;
        console.log(`Hi I am ${this.name}`);
        setTimeout(() => {
            this.next();
        }, 0);
    }
    eat (name) {
        var that = this;
        var fn = (function (n) {
            return function () {
                console.log(`I am eating ${n}`)
                that.next();
            }
        })(name);
        this.taskList.push(fn);
        return this;
    }
    sleepFirst (time) {
        var that = this;
        var fn = (function (t) {
            return function () {
                setTimeout(() => {
                    console.log(`等待了${t}秒...`)
                    that.next();
                }, t * 1000);  
            }
        })(time);
        this.taskList.unshift(fn);
        return this;
    }
    sleep (time) {
        var that = this
        var fn = (function (t) {
            return function () {
                setTimeout(() => {
                    console.log(`等待了${t}秒...`)
                    that.next();
                }, t * 1000); 
            }
        })(time);
        this.taskList.push(fn);
        return this;
    }
    next () {
        var fn = this.taskList.shift();
        fn && fn();
    }
}
function LazyMan(name) {
    return new LazyManClass(name);
}
LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(4).eat('junk food');

为什么要写自执行函数自执行函数,感觉有点多余

function lazyMan(name) {
    console.log(`Hi I am ${name}`);
    const obj = {
        task: [],
        next() {
            // 完成一个任务之后继续完成下面的直到没有任务为止
            const task = this.task.shift();
            task && task();
        },
        sleep(second) {
            this.task.push(() => {
                console.log(`等待${second}秒...`)
                setTimeout(() => {
                    this.next();
                }, second * 1000);
            })
            return this;
        },
        eat(name) {
            this.task.push(() => {
                console.log(`I am eating ${name}`)
                this.next();
            })
            return this;
        },
        sleepFirst(second) {
            this.task.unshift(() => {
                console.log(`等待${second}秒...`);
                setTimeout(() => {
                    this.next();
                }, second * 1000);
            })
            return this;
        }
    };

    // 先等收集任务
    setTimeout(() => {
        // 收集好之后开始第一个任务
        obj.next();
    })
    return obj;
}

lazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(10).eat('junk food');

zwmmm avatar Jul 15 '19 07:07 zwmmm

      class LazyMan {
        constructor(name) {
          this.tasks = [];
          //  启动 tasks,利用 then的 异步原理拿到已经填充好的tasks
          Promise.resolve().then(() => {
            this.nextTick()
          })
          console.log(`hi i am ${name}`);
        }

        sleep(delay) {
          this.tasks.push(() => {
            setTimeout(() => {
              this.nextTick();
            }, delay * 1000);
          });

          return this;
        }

        sleepFirst(delay) {
          // unshift 插队到最前面
          this.tasks.unshift(() => {
            setTimeout(() => {
              this.nextTick();
            }, delay * 1000);
          });
          return this;
        }

        eat(what) {
          this.tasks.push(() => {
            console.log(`eating ${what}`);
            this.nextTick();
          });

          return this;
        }

        nextTick() {
          this.tasks.length && this.tasks.shift()();
        }
      }

NathanHan1 avatar Jul 15 '19 11:07 NathanHan1

class LazyMan {
        constructor(name) {
            this.name = name;
            console.log(`Hi, I am ${name}`)
            this.taskQueue = []
            setTimeout(() => {
                this.start()
            })
        }

        async start() {
            for (let task of this.taskQueue) {
                await task()
            }
        }

        eat(dinner) {
            this.taskQueue.push(() => {
                console.log(`I am eating ${dinner}`)
            })
            return this;
        }

        wait(time) {
            return () => new Promise(resolve => {
                setTimeout(() => {
                    console.log(`waiting ${time} second`)
                    resolve()
                }, time * 1000)
            })
        }

        sleep(time) {
            this.taskQueue.push(this.wait(time))
            return this;
        }

        sleepFirst(time) {
            this.taskQueue.unshift(this.wait(time))
            return this
        }
    }

    // new LazyMan('test1').sleep(2).eat('lunch')
    // new LazyMan('test2').eat('lunch').sleep(5).eat('dinner')
    new LazyMan('test3').eat('lunch').eat('dinner').sleepFirst(2).sleep(3).eat('junk food')

wangliang1124 avatar Jul 16 '19 04:07 wangliang1124

function LazyMan(str) { if (this.constructor !== LazyMan) { return new LazyMan(str) } this.willDoThing= [] this.firstDoing = [] this.firstSleep = false this._init(str) } LazyMan.prototype.init = function(str) { console.log(Hi I am ${str}); Promise.resolve().then( => { this.startDoing() }) return this } LazyMan.prototype.startDoing = async function() { if (this.firstSleep) { await this.firstDoing0 this.willDoThing.forEach( async (v) => {await v()} ) }else { this.willDoThing.forEach( async (v) => {await v()} ) } }

LazyMan.prototype.sleepFirst = function(time) { this.firstSleep = true this.firstDoing.push(async() => { await sleep(time) console.log('first sleep'+time); }) return this }

LazyMan.prototype.sleep = function(time) { this.willDoThing.push(async() => { await sleep(time) console.log('sleep'+time); }) return this }

function sleep(time) { return new Promise((a,b) => { setTimeout(()=> a() ,time) }) } LazyMan('zz').sleep(1000).sleepFirst(2000)

//备注其他功能就给willdoingThing添加fn就可以了,只是试验了一下两个sleep函数,多了一个判断

Hunterang avatar Jul 16 '19 09:07 Hunterang

function LazyMan(name) {
  console.log(`Hi I am ${name}`);

  const logArr = [];

  const executor = {
    _status: 'stoped',
    async _actor() {
      while (logArr.length) {
        const { wait, text } = logArr.shift();
        if (wait) await new Promise(resolve => setTimeout(resolve, wait));
        console.log(text);
      }
      this._status = 'stoped';
    },
    async dispatch() {
      if (this._status === 'running') return;
      this._status = 'running';
      await new Promise(resolve => setTimeout(resolve, 0));
      this._actor();
    },
  };

  return {
    eat(food) {
      logArr.push({
        wait: 0,
        text: `I am eating ${food}`,
      });
      executor.dispatch();
      return this;
    },

    sleepFirst(second) {
      logArr.unshift({
        wait: second * 1000,
        text: `等待了 ${second} 秒...`,
      });
      executor.dispatch();
      return this;
    },

    sleep(second) {
      logArr.push({
        wait: second * 1000,
        text: `等待了 ${second} 秒...`,
      });
      executor.dispatch();
      return this;
    },
  };
}

AsakuraC avatar Jul 16 '19 11:07 AsakuraC

function LazyMan(name) {
      var o = new Object();
      o.name = name;

      console.log(`Hi I am ${o.name}`);

      o.message = [];
      setTimeout(() => {
        o.next();
      }, 0);

      o.eat = function (food) {
        var fn = function () {
          console.log(`I am eating ${food}`);
          o.next();
        }

        o.message.push(fn);
        return o;
      }

      o.sleepFirst = function (time) {
        var fn = function () {
          setTimeout(function () {
            console.log(`等待了${time}秒...`);
            o.next();
          }, time * 1000);
        }
        o.message.unshift(fn);
        return o;
      }

      o.sleep = function (time) {
        var fn = function () {
          setTimeout(function () {
            console.log(`等待了${time}秒...`);
            o.next();
          }, time * 1000);
        }
        o.message.push(fn);
        return o;
      }

      o.next = function () {
        var fn = o.message.shift();
        fn && fn();
      }
      return o;
    }

    LazyMan('Jack').eat('lunch').eat('dinner').sleepFirst(5).sleep(10).eat('junk food');

wycyftk avatar Jul 18 '19 03:07 wycyftk

详情

dongCode avatar Jul 22 '19 09:07 dongCode

class LazyManClass {
    constructor (name) {
        this.name = name
        this.task = []
        console.log('Hi I am ', name)
        setTimeout(() => {
            this.next()
        }, 0)
    }
    eat (str) {
        this.task.push(() => {
            console.log('I am eating ', str)
            this.next()
        })
        return this
    }
    sleep (n) {
        this.task.push(() => {
            setTimeout(() => {
                console.log('等待了' + n + 's')
                this.next()
            }, n)
        })
        return this
    }
    sleepFirst (n) {
        this.task.unshift(() => {
            setTimeout(() => {
                console.log('等待了' + n + 's')
                this.next()
            }, n)
        })
        return this
    }
    next () {
        let fn = this.task.shift()
        fn && fn()
    }
};

let LazyMan = function (name) {
    return new LazyManClass(name)
};

// LazyMan('Tony');
// Hi I am Tony

// LazyMan('Tony').sleep(10).eat('lunch');
// Hi I am Tony
// 等待了10秒...
// I am eating lunch

// LazyMan('Tony').eat('lunch').sleep(10).eat('dinner');
// Hi I am Tony
// I am eating lunch
// 等待了10秒...
// I am eating diner

LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(10).eat('junk food');
// Hi I am Tony
// 等待了5秒...
// I am eating lunch
// I am eating dinner
// 等待了10秒...
// I am eating junk food

这道题的关键点有如下几个:

  • 链式调用,通过返回 this 实现
  • 内部需要维护一个 taskList ,根据不同逻辑,向 taskList 中push 、shift、unshift 执行函数
  • 每执行一个task,需要继续执行后续 task,这通过 next 函数实现。

yingye avatar Jul 25 '19 07:07 yingye

@zeroone001 请问为什么每个函数要通过闭包的形式,参考@lvwxx的形式,不需要闭包也能实现,请问使用闭包是出于什么考虑么

chaoranfeng avatar Jul 26 '19 08:07 chaoranfeng

class MyClass{
  constructor(name){
    this.timer=null;
    this.taskList=[];
    console.log(`Hi I am ${name}`)
  }
  sleep(time){
    this.run(async ()=>{
      await new Promise(resolve=>setTimeout(resolve,time*1000))
      console.log(`等待了${time}秒...`)
    })
    return this
  }
 sleepFirst(time){
    this.run(async ()=>{
      await new Promise(resolve=>setTimeout(resolve,time*1000))
      console.log(`等待了${time}秒...`)
    },'unshift')
    return this
  }
  run(fun,act='push'){
    if(this.timer)clearTimeout(this.timer);
    this.taskList[act](fun)
    this.timer=setTimeout(this.next.bind(this));
    return this
  }
 
  async next(){
    let current;
    while(current=this.taskList.shift()){
       await current()
    }
  }
  eat(name){
    this.run(()=>console.log(`I am eating ${name}`))
    return this
  }
  
}
function LazyMan(name){
  return new MyClass(name)
}

zuotang avatar Jul 27 '19 01:07 zuotang

const LazyManClass = class {
  constructor(name) {
    console.log('Hi I am ' + name)
    this.isPendding = false
    this.sleepCb = [[]]
    this.sleeping = Promise.resolve()
  }
  get len() {
    return this.sleepCb.length
  }
  sleepFirst(time) {
    this.sleep(time)
    return this
  }
  sleep(time) {
    if (this.isPendding) {
      this.sleepCb[this.len - 1].push(() => this.sleep(time))
    } else {
      this.sleepCb.push([])
      const mySleepCb = this.sleepCb[this.len - 1]
      this.sleeping = new Promise(resolve => {
        this.isPendding = true
        setTimeout(() => {
          console.log(`等待了${time}秒...`)
          this.isPendding = false
          resolve()
        }, time * 1000)
      })
      this.sleeping.then(() => {
        mySleepCb.forEach(fun => fun.call(this))
      })
    }
    return this
  }
  eat(food) {
    if (this.isPendding) {
      this.sleepCb[this.len - 1].push(() => this.eat(food))
    } else {
      console.log('Hi I eating  ' + food)
    }
    return this
  }
}

const LazyMan = name => new LazyManClass(name)

yesixuan avatar Jul 29 '19 09:07 yesixuan

class LazyManClass {
  constructor(name){
    this.name = name
    this.queue = [] //队列
    console.log(`Hi I am ${this.name}`)
    setTimeout(() => {
      this.nextTask()
    }, 0);
  }

  sleep(time){
    let task = () => {
      setTimeout(() => {
        console.log(`等待了${time}秒...`)
        this.nextTask()
      }, time*1000);
    }
    this.queue.push(task)
    return this
  }

  sleepFirst(time){
    let task = () => {
      setTimeout(() => {
        console.log(`等待了${time}秒...`)
        this.nextTask()
      }, time*1000);
    }
    this.queue.splice(0, 0, task)
    return this
  }

  eat(food){
    const task = () => {
      console.log(`I am eating ${food}`)
      this.nextTask()
    }
    this.queue.push(task)
    return this
  }
  //下一任务
  nextTask(){
    let task = this.queue.shift()
    task && task()
  }
}

function LazyMan(name){
  return new LazyManClass(name)
}

wangMengLiang avatar Jul 29 '19 12:07 wangMengLiang

function LazyMan(name) {
    if (this instanceof LazyMan) {
        this.name = name;
        this.taskQueue = [];
        this.firstTaskQueue = [];
        console.log('Hi I am Tony');
        return this;
    } else {
        return new LazyMan(name);
    }
}

LazyMan.prototype.eat = function(food) {
	var func = function() {
		console.log('I am eating ' + food);
	};
	var _this = this;
	this.isSleeping ? 
		this.taskQueue.push(func) 
			: setTimeout(function() {
				if (_this.isSleepFirst) {
					_this.firstTaskQueue.push(func) 
				} else {
					console.log('I am eating ' + food)
				}
			});
	return this;
	
}

LazyMan.prototype.sleep = function(time) {
	var _this = this;
	this.isSleeping = true;
	setTimeout(function() {
		_this.isSleeping = false;
		console.log('等待了' + time + '秒...');
		const func = _this.taskQueue.shift();
		func.call(_this);
	}, time * 1000)
	return this;
}

LazyMan.prototype.sleepFirst = function(time) {
	var _this = this;
	this.isSleepFirst = true;
	setTimeout(function() {
		_this.isSleepFirst = false;
		console.log('等待了' + time + '秒...');
		_this.firstTaskQueue.forEach(func => {
			func.call(_this);
		});
	}, time * 1000)
	return this;
}

wenqingxin avatar Jul 29 '19 15:07 wenqingxin

const LazyManClass2 = class {
  constructor(name) {
    console.log('Hi I am ' + name)
    this.tasks = []
    setTimeout(() => this.next())
  }
  sleepFirst(time) {
    this.tasks.unshift(() => {
      setTimeout(() => {
        console.log(`等待了${time}秒...`)
        this.next()
      }, time * 1000)
    })
    return this
  }
  sleep(time) {
    this.tasks.push(() => {
      setTimeout(() => {
        console.log(`等待了${time}秒...`)
        this.next()
      }, time * 1000)
    })
    return this
  }
  eat(food) {
    this.tasks.push(() => {
      console.log('Hi I eating  ' + food)
      this.next()
    })
    return this
  }
  next(...args) {
    const task = this.tasks.shift()
    task && task.call(this, ...args)
  }
}

const LazyMan = name => new LazyManClass2(name)

yesixuan avatar Jul 30 '19 02:07 yesixuan

来一个使用 async await 解题的方案

const LazyManClass2 = class {
  constructor(name) {
    console.log('Hi I am ' + name)
    this.tasks = []
    setTimeout(() => this.run())
  }
  sleepFirst(time) {
    this.tasks.unshift(async() => {
      return new Promise(resolve => {
        setTimeout(() => {
          console.log(`等待了${time}秒...`)
          resolve()
        }, time * 1000)
      })
    })
    return this
  }
  sleep(time) {
    this.tasks.push(async() => {
      return new Promise(resolve => {
        setTimeout(() => {
          console.log(`等待了${time}秒...`)
          resolve()
        }, time * 1000)
      })
    })
    return this
  } 
  eat(food) {
    this.tasks.push(async() => {
      console.log('Hi I eating ' + food)
    })
    return this
  }
  run() {
    this.tasks.reduce(async(prev, curr) => {
      await prev
      return curr()
    }, Promise.resolve())
  }
}

const LazyMan = name => new LazyManClass2(name)

yesixuan avatar Jul 30 '19 06:07 yesixuan

class LazyManClass {
  constructor(name) {
    this.queues = [];
    console.log(`Hi I am ${name}!`);
    setTimeout(() => {
      this.next();
    }, 0);
  }
  eat(food) {
    this.queues.push(() => {
      console.log(`I am eating ${food}`)
      this.next();
    });
    return this;
  }
  sleep(seconds) {
    this.queues.push(() => {
      setTimeout(() => {
        console.log(`等待了${seconds}秒`);
        this.next();
      }, seconds * 1000)
    });
    return this;
  }
  sleepFirst(seconds) {
    this.queues.unshift(() => {
      setTimeout(() => {
        console.log(`等待了${seconds}秒`);
        this.next();
      }, seconds * 1000)
    });
    return this;
  }
  next() {
    if (this.queues.length){
      const fn = this.queues.shift();
      fn && fn();
    }
  }
}

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

LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(4).eat('junk food');

ppppp-x-x avatar Jul 31 '19 01:07 ppppp-x-x

感觉立即执行函数有点多余,没必要加上

    class LazyMats {
      constructor(name){
        this.name=name;
        this.arr=[];
        console.log(`Hi I am ${this.name}`)
        setTimeout(() => this.next(), 0);
      }
      eat(lunch){
        let fast=()=>{
          console.log(lunch)
          this.next()
        }
        this.arr.push(fast)
        return this;
      }
      sleep(time){
        let fast=()=>{
          setTimeout(()=>{
            console.log(`等待了${time}秒`)
            this.next()
          }, time*1000);
        }
        this.arr.push(fast)
        return this;
      }
      sleepFirst(time){
        let fast=()=>{
          setTimeout(()=>{
            console.log(`首先等待了${time}秒`)
            this.next()
          }, time*1000);
        }
        this.arr.unshift(fast);
        return this;
      }
      next(){
        let fn=this.arr.shift()
        fn&&fn()
      }
    }

    function LazyMan(name){
      return new LazyMats(name)
    }
    LazyMan('Tony').eat('lunch').sleep(1).eat('dinner').sleepFirst(2).eat('junk food')

SpengF avatar Aug 01 '19 02:08 SpengF

interface ILazyMan { name: string stack: Array<Function>

eat(food: string): any

sleep(wait: number): any

sleepFirst(wait: number): any

next()

}

// 这里面需要注意的是, 等待是异步操作, 我们先用同步将所有的事件都放到栈里面, 然后, 在通过next进行顺序执行, // 类似于 koa 里面的 next机制 class LazyMan implements ILazyMan { name: string; stack: Array<Function>;

constructor(name: string) {
    this.name = name;
    this.stack = [];
    console.log(`我是${this.name}`);
    // 这个 setTimeout 用来先让他们将同步完成, 完成之后, 在进行异步执行
    setTimeout(() => {
        this.next();
    });
}

sleep(wait: number) {
    this.stack.push(() => {
        setTimeout(() => {
            console.log(`我休息了${wait}s`);
            this.next();
        }, wait * 1000);
    });
    return this;
}

eat(food: string): any {
    this.stack.push(() => {
        console.log(`我正在吃${food}`);
        this.next();
    });
    return this;
}

sleepFirst(wait: number): object {
    this.stack.unshift(() => {
        setTimeout(() => {
            console.log(`我先休息了${wait}s`);
            this.next();
        }, wait * 1000);
    });
    return this;
}


next() {
    const fn = this.stack.shift();
    fn && fn();
}

}

let lazyNan = (name: string): ILazyMan => new LazyMan(name);

lazyNan('小芳').eat('firstFood').eat('lunch').sleepFirst(5).sleep(5).eat('dinner');

montage-f avatar Aug 01 '19 04:08 montage-f

function LazyMan (name){
    class Man{
        constructor(name){
            this.name = name
            this.say()
            this.eventList = []  //事件队列
            this.dispatchEvent = false //事件调度,开启事件队列执行
        }
        say(){
            console.log(`hi i am ${this.name}`)
            return this
        }
        eat(name){  
          this.dispatchEvent = true
          this.eventList.push((fn)=>{
             console.log(`i am eating ${name}`)
             fn.call(this,true)
          })
          Promise.resolve().then(()=>{ this.pollEvent() })  
          return this
        }
        sleep(time){
          this.dispatchEvent = true
          this.eventList.push((fn)=>{
              const now = new Date() //sleep settimeout 来实现
              setTimeout(()=>{
                fn.call(this,true)
              },time*1000)
              
          })  
          Promise.resolve().then(()=>{ this.pollEvent() })  
          return this 
        }
        sleepFirst(time){
          this.dispatchEvent = true
          this.eventList.unshift((fn)=>{
              const now = new Date() // sleep 用超时来实现(个人推荐这里用settime来实现)
              while( Date.parse( new Date() ) - Date.parse(now) < 1000 * time   ){
                  continue
              }
              fn.call(this,true)
          }) 
          Promise.resolve().then(()=>{ this.pollEvent() })  
          return this    
        }
        pollEvent(hasPoll){
            //事件循环执行器
            if(!this.dispatchEvent && !hasPoll ) return
            this.dispatchEvent = false
            let current = this.eventList.shift()
            current  && current.call(this,this.pollEvent)
        }
    }
   return new Man(name)
}

GoodLuckAlien avatar Aug 07 '19 02:08 GoodLuckAlien

function LazyMan (name) {
  console.log(`Hi I am ${name}`);
  let a = {
    sleeping: false,
    firstSleep: false,
    init: true,
    sleepArr: new Set([]),
    firstSleepTime: 0,
    sleep (time) {
      if (!checkSleep(this.sleep.bind(this, time))) {
        return this;
      }
      this.sleeping = true;
      setTimeout(() => {
        this.sleeping = false;
        handleSleep();
      }, time * 1000);
      return this;
    },
    eat (val) {
      if (!checkSleep(this.eat.bind(this, val))) {
        return this;
      }
      console.log(`I am eating ${val}`);
      return this;
    },
    sleepFirst (time) {
      this.firstSleepTime += time * 1000;
      return this;
    }
  }
  function checkSleep(fn) {
    if (a.sleeping || a.init) {
      a.sleepArr.add(fn);
      return false;
    } else {
      return true;
    }
  }
  setTimeout(() => {
      setTimeout(() => {
        a.init = false;
        handleSleep();
      }, a.firstSleepTime);
  }, 0);
  function handleSleep () {
    const sleepArr = a.sleepArr;
    for (let item of sleepArr) {
      item();
      sleepArr.delete(item);
      if (a.sleeping) {
        break;
      }
    }
  }
  return a;
}

haojiasheng avatar Aug 07 '19 15:08 haojiasheng

用promise实现了一下,只写了sleep、eat 方法,sleepFirst 类似sleep

function LazyMan(name) {
	let progress = new Promise((resolve, reject) => {
		console.log(`Hi I am ${name}`);
		resolve();
	})
	return {
		sleep: function (time) {
			progress = progress.then(() => {
				console.log(`等待了${time}毫秒`);
				return new Promise((resolve, reject) => {
					setTimeout(() => resolve(), time)
				})
			})
			return this
		},
		eat: function(text) {
			progress = progress.then(() => {
				return new Promise((resolve, reject) => {
					console.log(`I am eating ${text}`);
					resolve();
				})
			})
			return this
		}
	}
}

image

AChengXuYuan avatar Aug 08 '19 17:08 AChengXuYuan

 class LazyManClass {
    tasklist = []
    constructor (name) {
      console.log(`Hi I am ${name}`)
      setTimeout(() => {
        this.tasklist.reduce((preState, item) => {
          return preState.then(item)
        }, Promise.resolve())
      }, 0)
    }
    eat (foods) {
      this.tasklist.push(() => console.log(`I am eating ${foods}`))
      return this
    }
    sleep (time) {
      this.tasklist.push(() => {
        return new Promise((res, rej) => {
          setTimeout(() => {
            res(console.log(`等待了${time}秒...`))
          }, time * 1000)
        })
      })
      return this
    }
    sleepFirst (time) {
      this.tasklist.unshift(() => new Promise((res, rej) => {
        setTimeout(() => {
          res(console.log(`等待了${time}秒...`))
        }, time * 1000)
      }))
      return this
    }
  }
 const LazyMan = function (name) {
    return new LazyManClass(name)
 }

maginapp avatar Aug 14 '19 03:08 maginapp

我用了很非常简单的方法实现的,不知道是否正确,请各位朋友指正。 思路如下: 1.给LazyMan设置是否休息的标志isSleep,sleep和sleepFirst方法都能将isSleep设置为真,并设置休息的时间sleepTime, eat方法根据isSleep决定是否延时执行 2.sleepFirst有优先执行权,sleepFirst中不设置setTimeout 3.要实现链式调用,所以每个方法都要返回this

class LazyManObject{
  constructor(str) {
    console.log('I am ' + str);
    this.isSleep = false;
    this.sleepTime = 0;
  }
  eat(str) {
    setTimeout(() => {
      if (!this.isSleep) { 
        console.log('I am eating ' + str);
      } else {
        setTimeout(() => {
          console.log('I am eating ' + str);
          this.sleepTime = 0;
          this.isSleep = false;
          return this;
        }, this.sleepTime);
      }
    })
    return this;
  }
  sleepFirst(num) {
    this.sleepTime = num * 1000;
    this.isSleep = true;
    return this;
  }
  sleep(num) {
    setTimeout(() => {
      this.sleepTime = num * 1000;
      this.isSleep = true;
    })
    return this;
  }
}
function LazyMan(str) {
  return new LazyManObject(str);
}

LazyMan('Jack').eat('breakfast').sleep(10).eat('lunch').sleepFirst(5);

shuijingyue avatar Aug 15 '19 01:08 shuijingyue

class LazyManClass {
    constructor(name) {
        this._taskList = [];
        console.info(`Hi I am ${name}`);
    }

    eat(foodName) {
        this._addTask(() => {
            console.info(`I am eat ${foodName}`);
            return Promise.resolve();
        });
        return this;
    }

    sleep(seconds, first = false) {
        let callback = () => new Promise((resolve) => {
            setTimeout(() => {
                resolve();
                console.info(`等待了${seconds}秒钟...`);
            }, seconds * 1000)
        });
        this._addTask(callback, first);
        return this;
    }

    sleepFirst(seconds) {
        return this.sleep(seconds, true);
    }

    _addTask(callback, first = false) {
        let task = () => callback.call(this).finally(this._execute.bind(this));

        if (first) {
            this._taskList.unshift(task);
        } else {
            this._taskList.push(task);
        }

        this._execute();
    }

    _execute() {
        if (this._taskList.length) {
            clearTimeout(this._timeout);
            this._timeout = setTimeout(() => {
                if (this._taskList.length) {
                    let task = this._taskList.shift();
                    task();
                }
            }, 0);
        }
    }
}

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

LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(10).eat('junk food');

yy921 avatar Aug 16 '19 06:08 yy921

感觉那些 next 的都是正统猿啊,学习了😂

function outSleep(t) {
  return new Promise(r => {
    setTimeout(() => {
      console.log("");
      console.log(`...outSleep ${t}`);
      r();
    }, 1000 * t);
  });
}

function LazyMan(name) {
  const lazy = {
    _cbs: [],
    _timer: null,
    _init() {
      if (name) console.log(`Hi I am ${name}`);
      return this;
    },
    async _run() {
      console.log("");
      console.log(`===start`);
      console.log(this._cbs);
      console.log("");
      for (let i = 0; i < this._cbs.length; i++) {
        const fn = this._cbs[i];
        await fn();
      }
      return this;
    },
    eat(food) {
      this._cbs.push(function eat() {
        console.log(`I am eating ${food}`);
      });
      clearTimeout(this._timer);
      this._timer = setTimeout(() => {
        this._run();
      }, 0);
      return this;
    },
    sleep(t) {
      this._cbs.push(async function sleep() {
        await outSleep(t);
      });
      return this;
    },
    sleepFirst(t) {
      this._cbs.unshift(async function sleepFirst() {
        await outSleep(t);
      });
      return this;
    }
  };

  return lazy._init();
}

Hi I am Tony

===start
[ [AsyncFunction: sleepFirst],
  [Function: eat],
  [Function: eat],
  [AsyncFunction: sleep],
  [Function: eat] ]


...outSleep 5
I am eating lunch
I am eating dinner

...outSleep 1
I am eating junk food

JackFGreen avatar Aug 16 '19 07:08 JackFGreen

简单点

function LazyMan(name) {
    console.log('Hi I am ' + name)
    const addTask = function (task, pos = 'last') {
        if (!this.start) {
            this.start = true
            this.startTask()
        }
        if (pos === 'last') {
            this.task.push(task)
        } else {
            this.task.unshift(task)
        }
    }
    const startTask = function () {
        setTimeout(async () => {
            const task = [...this.task]
            this.task = []
            for (let i = 0; i < task.length; i++) {
                let res = await task[i]()
            }
            this.start = false
        })
    }
    const task = []
    const sleep = function (time, pos = 'last') {
        const taskFuc = () => {
            return new Promise((resolve) => {
                setTimeout(() => {
                    console.log('等待了', time)
                    resolve('sad')
                }, time * 1000)
            })
        }
        this.addTask(taskFuc, pos)
        return this
    }
    const eat = function (food) {
        this.addTask(() => console.log('i am eat', food))
        return this
    }
    const sleepFirst = function (time) {
        this.sleep(time, 'first')
        return this
    }
    return {
        task,
        sleep,
        eat,
        startTask,
        start: false,
        addTask,
        sleepFirst,
    }
}

livetune avatar Aug 18 '19 04:08 livetune

为什么需要立即执行函数?

   var fn = (function (t) {
            return function () {
                setTimeout(() => {
                    console.log(`等待了${t}秒...`)
                    that.next();
                }, t * 1000); 
            }
        })(time);

直接如下不行吗?

            var fn = function () {
                setTimeout(() => {
                    console.log(`等待了${t}秒...`)
                    that.next();
                }, t * 1000); 
            };

liuxingit avatar Aug 18 '19 11:08 liuxingit

class LazyManClass {
    constructor(name) {
        this.name = name;
        this.callback = [];
        this.firstStack = [];
        this.stack = [];
        console.log(`Hi I am ${this.name}`);
        setTimeout(this.next.bind(this), 0);
    }

    eat(food) {
        this.stack.push(() => {
            return new Promise((resolve, reject) => {
                console.log(`I am eating ${food}`);
                resolve();
            });
        });
        return this;
    }
    sleep(seconds) {
        this.stack.push(() => {
            return new Promise((resolve, reject) => {
                console.log(`等待了${seconds}秒`);
                setTimeout(resolve, seconds * 1000);
            });
        });
        return this;
    }

    sleepFirst(seconds) {
        this.firstStack.push(() => {
            return new Promise((resolve, reject) => {
                console.log(`等待了${seconds}秒`);
                setTimeout(resolve, seconds * 1000);
            });
        });
        return this;
    }

    next() {
        if (this.firstStack.length > 0) {
            this.firstStack.shift()().then(this.next.bind(this));
        } else if (this.stack.length > 0) {
            this.stack.shift()().then(this.next.bind(this));
        }
    }
}

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

Aras-ax avatar Aug 19 '19 01:08 Aras-ax

以上大部分是以事件队列的算法实现,我这里提供发布订阅的一种算法,供大家参考:

class Event {
    maps = {};
    fire(type) {
        const stack = this.maps[type] || [];
        stack.every(listener => listener());
    }

    listen(type, listener) {
        if (!this.maps.hasOwnProperty(type)) {
            this.maps[type] = [];
        }

        this.maps[type].push(listener);
    }

    remove(type, listener) {
        const index = this.maps.indexOf(listener);
        this.maps.splice(index, 1);
    }
}

let EventItem = new Event(); 
let init = false;
function LazyMan(name){
    this.sleepState = false;
    if(!init){
        console.log('Hi I am ' + name);
        init = true;
        return new LazyMan(name);
    }
}

LazyMan.prototype.sleep = function(time){
    function s(){
        this.sleepState = true;
        setTimeout(() => {
            console.log('等待了' + time + '秒...');
            this.sleepState = false;
            EventItem.fire('sleepOver')
        }, time * 1000);
    }
    if(!this.sleepState){
        s()
    }else{
        EventItem.listen('sleepFirstOver', () => {
            s()
        });
    }
    return this;
}

LazyMan.prototype.sleepFirst = function(time){
    this.sleepState = true;
    setTimeout(() => {
        console.log('等待了' + time + '秒...');
        this.sleepState = false;
        EventItem.fire('sleepFirstOver')
    }, time * 1000);
    return this;
}

LazyMan.prototype.eat = function(type){
    if(!this.sleepState){
        console.log('I am eating ' + type)
    }else{
        EventItem.listen('sleepOver', () => {
            console.log('I am eating ' + type)
        });
    }
    return this;
}

LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(10).eat('junk food');

lvzhiyi avatar Aug 20 '19 09:08 lvzhiyi

或许 next 的逻辑不应该放在队列里,队列应该做的只是保证根据优先级和先入先出来决定谁先出

class LazyMan {
	constructor(name) {
		this.name = name;
		this.queue = [];
		console.log(`Hi I am ${name}`);

		setTimeout(this.apply.bind(this));
	}

	eat(something) {
		this.queue.push(() => console.log(`I am eating ${something}`));
		return this;
	}

	sleep(time) {
		this.queue.push(async () => {
			console.log(`等待了${time}秒...`);
			return new Promise(res => setTimeout(res, time * 1000))
		})
		return this;
	}

	sleepFirst(time) {
		this.queue.unshift(async () => {
			console.log(`等待了${time}秒...`);
			return new Promise(res => setTimeout(res, time * 1000))
		})
		return this;
	}

	async apply() {
		const queue = this.queue;
		while (queue.length) {
			const todo = queue.shift();
			await todo();
		}
	}
}

HowGraceU avatar Aug 24 '19 03:08 HowGraceU

class LazyMan{
    constructor (name) {
        this.name = name
        this.sleep = 0
        this.sleepFirst = 0
        console.log(`Hi I am ${this.name}`)
    }
    eat (what) {
        setTimeout(()=>{setTimeout(()=>{console.log(`I am eating ${what}`)}, this.sleepFirst)}, this.sleep)
        return this
    }
    Sleep (time) {
        this.sleep = time
        return this
    }
    SleepFirst (time) {
        this.sleepFirst = time
        return this
    }
}
new LazyMan('Tony').eat('lunch').eat('dinner').Sleep(1000).eat('dinnerend').SleepFirst(2000)

tigerdone avatar Aug 29 '19 08:08 tigerdone

image 有没有大佬解答一下,这里传立即执行函数的返回值(函数)和直接传红字部分的函数,有什么区别吗

立即执行函数的作用是在内部函数还没有执行的时候就已经为内部函数绑定好了对应参数的值,如果不用立即函数的话也可以用bind方法

var name = '小明'
var fn = function (n){
 console.log(`I am eating ${n}`)
 this.next()
}.bind(null, name)

上面的代码实际上是让fn等于下面这个函数:
function (){
 console.log(`I am eating 小明`)
 this.next()
}

这样一来无论你在什么地方执行fn都不需要传参数了,直接fn()不用参数也能达到和普通fn的fn(name )效果一样了

为什么不直接

        var fn = function () {
              console.log(`I am eating ${name}`)
              that.next();
          }

dunhuang avatar Sep 24 '19 08:09 dunhuang



// Lazyman 
    // 关键在于队列,taskQueue ,其实不是异步
    function _Lazyman(name) {
      return new Lazyman(name)
    }
    function Lazyman(name) {
      this.name = name
      this.taskQueue = []
      // 但是启动的必须是异步,先都加入到队列,然后异步按照顺序执行
      const asyncFunc = ()=>{
        setTimeout(()=>{
          console.log('I m '+ name)
          this.runNext() 
        }, 0)
      }
      this.taskQueue.push(asyncFunc)
      this.runNext() // 启动整个流程
    }

    Lazyman.prototype.eat = function(food) {
      this.taskQueue.push(
        // ()=>{
        // setTimeout(()=>{
        //   console.log('eating ' + food)
        //   this.runNext()
        // }, 0)
        // }

        ()=>{
          console.log('eating ' + food)
          this.runNext()
         }
      )
      return this
    }
    Lazyman.prototype.sleep = function(time) {
      this.taskQueue.push( ()=> {
        setTimeout(()=> {
          this.runNext()
        }, time)
      } )
      return this
    }
    Lazyman.prototype.runNext = function() {
      let fn = this.taskQueue.shift() // 取第一个
      fn && fn()
    }

    _Lazyman('kevin').eat('a').eat('b').sleep(3000).eat('c')

上面有的同学的思路很棒,就是不在队列的函数里面执行runNext,单独维护一个函数run整个queue里面的函数。

aeolusheath avatar Oct 12 '19 03:10 aeolusheath

function LazyMan(name) {
  console.log(`Hi I am ${name}`);
  let tasks = [];
  let run = () => {
    if (tasks.length) {
      let task = tasks.shift();
      task && task();
    }
  };
  setTimeout(() => {
    run();
  }, 0);

  return {
    sleep(time) {
      tasks.push(() => {
        setTimeout(() => {
          console.log(`等待了${time}秒...`)
          run();
        }, 1000 * time);
      });
      return this;
    },
    sleepFirst(time) {
      tasks.unshift(() => {
        setTimeout(() => {
          console.log(`等待了${time}秒...`)
          run();
        }, 1000 * time);
      });
      return this;
    },
    eat(what) {
      tasks.push(() => {
        console.log(`I am eating ${what}`);
        run();
      });
      return this;
    }
  }
}

// test
LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(10).eat('junk food');

shenxinle avatar Oct 20 '19 13:10 shenxinle

网上看到一个比较好的思路 [(https://www.jianshu.com/p/f1b7cb456d37)] 分析了考察的要点 “ 1.方法链式调用  2.类的使用和面向对象编程的思路  3.设计模式的应用  4.代码的解耦  5.最少知识原则,也即 迪米特法则(Law of Demeter)  6.代码的书写结构和命名 ”

youyidecai avatar Oct 20 '19 15:10 youyidecai

var _now = function() {return new Date()}
function LazyMan(name) {
    console.log(`Hi I am ${name}`)
    setTimeout(() => {}, 0);
    return this
}
LazyMan.prototype.eat = function (type) {
    setTimeout(() => {
        console.log(`I am eating ${type}`)
    }, 0);
    return this
};
LazyMan.prototype.sleep = function (sec) {
    var now = new Date();
    setTimeout(() => {
        while (_now() - now < sec * 1000) {}
        console.log(`等待了${sec}秒`);
    }, 0);
    return this
};
LazyMan.prototype.sleepFirst = function (sec) {
    var now = new Date();
    while (_now() - now < sec * 1000) {}
    console.log(`等待了${sec}秒`);
    return this
};

Pazzilivo avatar Oct 31 '19 03:10 Pazzilivo

class LazyManClass {
    constructor(name) {
        this.timeoutNum = 0
        this.timeoutArr = []
        this.index = 0
        console.log(`Hi I am ${name}`)
        setTimeout(() => {
            this.go()
        }, 0);
    }
    eat(type) {
        this.timeoutArr.push({
            timeout: this.timeoutNum,
            type
        })

        this.timeoutNum = 0

        return this
    }
    sleep(timeout) {
        this.timeoutNum += (timeout *= 1000)
        return this
    }
    sleepFirst(timeout) {
        this.timeoutArr = this.timeoutArr.map(item => {
            item.delay = true
            item.timeout = timeout * 1000
            return item
        })
        return this
    }
    go() {
        let curTimeoutItem = this.timeoutArr[this.index++]
        if (!curTimeoutItem) return false
        setTimeout(() => {
            do
                console.log(`I am eating ${curTimeoutItem.type}`)
            while ((curTimeoutItem = this.timeoutArr[this.index++]) && curTimeoutItem.delay);

            if (this.timeoutArr[--this.index]) this.go()
        }, curTimeoutItem.timeout);

    }
}

const LazyMan = name => {
    return new LazyManClass(name)
}

LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(10).eat('junk food')

ChandlerCao avatar Nov 13 '19 09:11 ChandlerCao

有大佬能解答下next()调用的时机吗,这个运行流程我有点看不懂=。=

这个跟event-loop(事件循环)有关,感兴趣的可以来了解一下我这篇文章:https://chen-cong.blog.csdn.net/article/details/97107219

ChenCong6837 avatar Dec 04 '19 03:12 ChenCong6837

LazyMan('Tony');
// Hi I am Tony

LazyMan('Tony').sleep(10).eat('lunch');
// Hi I am Tony
// 等待了10秒...
// I am eating lunch

LazyMan('Tony').eat('lunch').sleep(10).eat('dinner');
// Hi I am Tony
// I am eating lunch
// 等待了10秒...
// I am eating diner

LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(10).eat('junk food');
// Hi I am Tony
// 等待了5秒...
// I am eating lunch
// I am eating dinner
// 等待了10秒...
// I am eating junk food

yygmind avatar Dec 16 '19 03:12 yygmind

class LazyManClass { constructor(name) { this.name = name this.queue = [] console.log(Hi I am ${name}) setTimeout(() => { this.next() },0) }

sleepFirst(time) { const fn = () => { setTimeout(() => { console.log(等待了${time}秒...) this.next() }, time * 1000) } this.queue.unshift(fn) return this }

sleep(time) { const fn = () => { setTimeout(() => { console.log(等待了${time}秒...) this.next() },time * 1000) } this.queue.push(fn) return this }

eat(food) { const fn = () => { console.log(I am eating ${food}) this.next() } this.queue.push(fn) return this }

next() { const fn = this.queue.shift() fn && fn() } }

function LazyMan(name) { return new LazyManClass(name) } LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(4).eat('junk food');

lemon0815 avatar Dec 18 '19 04:12 lemon0815

你好,你的setTimeout里面没有乘1000,是毫秒,所以很快就输出了结果

在 2020年1月3日,下午2:42,GelaKola [email protected] 写道:

class LazyManClass { constructor(name) { this.name = name this.queue = [] console.log(Hi I am ${name}) setTimeout(() => { this.next() },0) }

sleepFirst(time) { const fn = () => { setTimeout(() => { console.log(等待了${time}秒...) this.next() }, time) } this.queue.unshift(fn) return this }

sleep(time) { const fn = () => { setTimeout(() => { console.log(等待了${time}秒...) this.next() },time) } this.queue.push(fn) return this }

eat(food) { const fn = () => { console.log(I am eating ${food}) this.next() } this.queue.push(fn) return this }

next() { const fn = this.queue.shift() fn && fn() } }

function LazyMan(name) { return new LazyManClass(name) } 你好你的这种写法如下调用,成功的输出了如下的输出,但是确没有真正等待5秒,4秒,而是一下子全部输出来的。

LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(4).eat('junk food'); // Hi I am Tony // 等待了5秒... // I am eating lunch // I am eating dinner // 等待了4秒... // I am eating junk food — You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/98?email_source=notifications&email_token=AGIDOG2TGU5EMXIFR6COSLLQ33M3TA5CNFSM4HGPR7PKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEIANLZY#issuecomment-570480103, or unsubscribe https://github.com/notifications/unsubscribe-auth/AGIDOG7NTMOVO2AA7X3VCNLQ33M3TANCNFSM4HGPR7PA.

lemon0815 avatar Jan 03 '20 10:01 lemon0815

function LazyMan(name) {
  return new function () {
    this.name = name
    console.log(`Hi I am ${this.name}`)
    this.events = []
    this.firstEvents = []
    this.eat = function (el) {
      this.events.push(() => console.log(`I am eating ${el}`))
      return this
    }
    this.sleepFirst = function(time){
      this.firstEvents = this.events.map((event)=>event)
      this.events = []
      setTimeout(()=>{
        time != 0 ? console.log(`等待了${time}秒...`) : null
        this.firstEvents.forEach(event => event())  
      },time * 1000)
      return this
    }
    this.sleep = function (time) {
      if(this.firstEvents==0) this.events = this.events.filter(event => event())  
      setTimeout(()=>{
        console.log(`等待了${time}秒...`)
        this.events.forEach(event => event())  
      },time * 1000)
      return this
    }

  }
}
LazyMan('Tony')
// Hi I am Tony

LazyMan('Tony').sleep(10).eat('lunch');
// Hi I am Tony
// 等待了10秒...
// I am eating lunch

LazyMan('Tony').eat('lunch').sleep(10).eat('dinner');
// Hi I am Tony
// I am eating lunch
// 等待了10秒...
// I am eating dinner


LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(10).eat('junk food');
// Hi I am Tony
// 等待了5秒...
// I am eating lunch
// I am eating dinner
// 等待了10秒...
// I am eating junk food

iceycc avatar Jan 09 '20 03:01 iceycc

function LazyManClass(name) {
  this.name = name;
  console.log(`Hi I am ${this.name}`);
  this.msgList = [];
  Promise.resolve().then(async () => {
    for(let i = 0; i < this.msgList.length; i ++) {
        if (this.msgList[i].time > 0) {
        await _sleep(this.msgList[i].time);
      }
      console.log(this.msgList[i].msg);
    }
  })
  async function _sleep(t) {
    await new Promise(resolve => setTimeout(() => resolve(), t*1000));
  }
  return this;
}

LazyManClass.prototype.eat = function(v) {
  this.msgList.push({
    time: 0,
    msg: `I am eating ${v}`,
  });
  return this;
};
LazyManClass.prototype.sleep = function(t) {
  this.msgList.push({
    time: t,
    msg: `等待了 ${t}秒...`,
  });
  return this;
};
LazyManClass.prototype.sleepFirst = function(t) {
  this.msgList.unshift({
    time: t,
    msg: `等待了 ${t}秒...`,
  });
  return this;
};

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

LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(10).eat('junk food');

zjiang121143210 avatar Jan 09 '20 09:01 zjiang121143210

class LazyManClass { constructor(name) { this.taskQueue = []
console.log(Hi I am ${name}) setTimeout(() => { this.next() }) } sleep(second) {
let task = () => { setTimeout(() => { console.log(等待了${second}秒...) this.next() }, second * 1000) } this.taskQueue.push(task) return this } sleepFirst(second) { let task = () => { setTimeout(() => { console.log(等待了${second}秒...) this.next() }, second * 1000)
} this.taskQueue.unshift(task) return this } eat(food) { let task = () => { console.log('I am eating', food) this.next() } this.taskQueue.push(task)
return this } next() { let fn = this.taskQueue.shift() fn && fn() } } function LazyMan(name) { return new LazyManClass(name) }

mahuimable avatar Feb 07 '20 03:02 mahuimable

class LazyMan {
  constructor(name){
    this.normalQueue = [];
    this.sleepFistQueue = [];
    this.name = name;
    this.start();
    return this;
  }
  start(){
    this.delay(0, async ()=>{
      let normalQueue = this.normalQueue;
      let sleepFistQueue = this.sleepFistQueue;
      
      // say hi
      console.log(`Hi I am ${this.name}`);
      
      // sleepFirstQueue
      while(sleepFistQueue.length){
        await sleepFistQueue.shift()();
      }
      
      // normalQueue
       while(normalQueue.length){
        await normalQueue.shift()();
      }
      
    })
  }
  delay(time = 0, fn){
    return new Promise((resolve, reject) => {
      window.setTimeout(()=>{
        fn && fn();
        resolve();
      }, time*1000);
    })
  }
  eat(food){
    this.normalQueue.push(() => {
      return this.delay(0, () => { console.log(`I am eating ${food}`)});
    });
    return this;
  }
  sleep(time){
     this.normalQueue.push(() =>{
      return this.delay(time, () => { console.log(`Delay ${time}s`)});
    });
    return this;
  }
  sleepFirst(time){
    this.sleepFistQueue.push(() =>{
      return this.delay(time, () => { console.log(`First delay ${time}s`)});
    });
    return this;
  }
}
// test case
new LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(10).eat('junk food');

Simmer-Jun avatar Feb 27 '20 08:02 Simmer-Jun

妈蛋,看了一遍大家的回答,发现我的写法最老派,果然是岁月不饶人...

function LazyMan(name) {
  // 防止不通过new来调用
  if (!(this instanceof LazyMan)) {
    return new LazyMan(name);
  }
  this.name = name;
  this.queue = [];
  console.log(`I'm ${this.name}`);

  return this.process();
}
LazyMan.prototype = {
  process() {
    clearTimeout(this.timer);
    this.timer = setTimeout(() => {
      let p = Promise.resolve();
      while (this.queue.length) {
        p = p.then(this.queue.shift());
      }
    }, 0);
    return this;
  },
  eat(name) {
    this.queue.push(() => {
      return new Promise(resolve => {
        console.log(name);
        resolve();
      });
    });
    return this.process();
  },
  sleep(sec) {
    this.queue.push(() => {
      return new Promise(resolve => {
        setTimeout(() => {
          console.log(`等待了${sec}秒...`);
          resolve();
        }, sec * 10); // 方便测试 应该为1000
      });
    });
    return this.process();
  },
  sleepFirst(sec) {
    this.queue.unshift(() => {
      return new Promise(resolve => {
        setTimeout(() => {
          console.log(`等待了${sec}秒...`);
          resolve();
        }, sec * 10); // 方便测试 应该为1000
      });
    });
    return this.process();
  }
};

// 测试
var instance = LazyMan("Tony")
  .eat("lunch")
  .eat("dinner")
  .sleepFirst(5)
  .sleep(10)
  .eat("junk food");

setTimeout(() => {
  console.log("----again----");
  instance
    .eat("lunch")
    .eat("dinner")
    .sleepFirst(5)
    .sleep(10)
    .eat("junk food");
}, 1000);

whosesmile avatar Mar 10 '20 06:03 whosesmile

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

class LazyManReduxStyle {
    constructor(name) {
        this.name = name;
        this.middlewares = [this._say()];
        this.sleepFirstMiddlewares = [];
        setTimeout(() => {
            this._run();
        });
    }
  
    sleepFirst(time) {
        time = time * 1000;
        this.sleepFirstMiddlewares.push(next => () => {
            setTimeout(() => {
                console.log(`Wake up after ${time} ms`);
                next && next();
            }, time);
        });
        return this;
    }
  
    sleep(time) {
        time = time * 1000;
        this.middlewares.push(next => () => {
            setTimeout(() => {
                console.log(`Wake up after ${time} ms`);
                next && next();
            }, time);
        });
        return this;
    }
  
    eat(food) {
        this.middlewares.push(next => () => {
            console.log(`Eat ${food}~`);
            next && next();
        });
        return this;
    }
  
    _say() {
        return next => () => {
            console.log(`Hi, this is ${this.name}`);
            next && next();
        };
    }
  
    _run() {
        this._applyMiddlewares([...this.sleepFirstMiddlewares, ...this.middlewares])();
    }
  
    _applyMiddlewares(middlewares) {
        const [lastActionGenerator, ...restActionGenerators] = middlewares.reverse(); 
        return compose(restActionGenerators)(lastActionGenerator());
    }
}
  
function compose(funcs) {
    return arg => funcs.reduce((acc, curr) => curr(acc), arg);
}

LazyMan('Hank').sleepFirst(3).eat('lunch').sleep(3).eat('dinner').sleepFirst(2);

最近看了下 Redux 中间件的原理,借鉴下他的思想写个 Lazyman 通过将下一个动作包裹成 next 放在前一个动作里面然后在适当的时机去调用 next,来实现流程的运行.

PS:这里的 sleepFirstMiddlewares 数组可以去掉,但是以前看到这题的时候他的要求是 sleepFirst 最先执行,但执行顺序与调用顺序相同,如果用 unshift 的话,无法实现执行顺序与调用顺序相同,所以就加了个新的数组,否则只用一个数组就够了

divasatanica avatar Apr 15 '20 03:04 divasatanica

提升个难度: LazyMan('Tony').sleepFirst(5) // 等待了5秒 // Hi i am Tony

Gumplefik avatar Apr 18 '20 08:04 Gumplefik

        function LazyMan(name) {
            console.log(`Hi I am ${name}`)
            let totalSleepFirst = 0
            let callbacks = []

            function fire() {
                if (totalSleepFirst) return
                if (callbacks.length === 0) return

                function run(){
                    if(callbacks.length === 0) return

                    callbacks.shift()().then(run)
                }

                run()
            }

            function eat(food) {
                new Promise(resolve => {
                    setTimeout(() => {
                        resolve()
                        callbacks.push(() => Promise.resolve(console.log(`I am eating ${food}`)))
                        fire()
                    }, 0)
                })

                return man
            }

            function sleepFirst(delay) {
                setTimeout(() => {
                    console.log(`等待了${delay}秒`)
                    totalSleepFirst -= delay
                    fire()
                }, (delay + totalSleepFirst) * 1000)
                totalSleepFirst += delay

                return man
            }

            function sleep(delay) {
                new Promise(resolve => {
                    setTimeout(() => {
                        resolve()
                        callbacks.push(() => new Promise(resolve => {
                            setTimeout(() => {
                                console.log(`等待了${delay}秒`)
                                resolve()
                            }, delay * 1000)
                        }))
                        fire()
                    }, 0)
                })

                return man
            }

            const man = {
                eat,
                sleepFirst,
                sleep
            }

            return man
        }

        LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleepFirst(3).sleep(10).eat('junk food');

liuyunzhuge avatar May 18 '20 12:05 liuyunzhuge

class LazyMan {
    task = []
    timer = null
    constructor() {
        return this.sayHi
    }
    sayHi = (name) => {
        console.log(`Hi I am ${name}`)
        return this
    }
    eat(food) {
        this.task.push({ type: 'eat', value: food })
        this.doIt()
        return this
    }
    sleep(time) {
        this.task.push({ type: 'sleep', value: time })
        this.doIt()
        return this
    }
    sleepFirst(time) {
        this.task.unshift({ type: 'sleep', value: time })
        this.doIt()
        return this
    }
    _sleep (time) {
        return new Promise(r => { setTimeout(() => { r() }, time * 1000) })
    }
    doIt () {
        if (this.timer) clearTimeout(this.timer)
        this.timer = setTimeout(async () => {
            for (let i = 0; i < this.task.length; i++) {
                const item = this.task[i]
                if (item.type === 'eat') {
                    console.log(`I am eating ${item.value}`)
                } else {
                    await this._sleep(item.value)
                }
            }
        }, 0)
    }
}

const lazyMan = new LazyMan()
lazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(10).eat('junk food')

Murphycx94 avatar May 19 '20 15:05 Murphycx94

function LazyMan(name) {
    console.log(`I am ${name}`);
    var task = [];
    function execute() {
	var fn = task.shift();
        fn && fn();	
    }
   // delay execute
    setTimeout(function() {
        execute();
    }, 0);
    function _sleep(n = 0) {
        console.log(`${name} is sleeping ${n}`);
        setTimeout(function() {
            execute();
        }, n * 1000);
    }
    function _eat(food) {
        console.log(`${name} is eating ${food}`);
        execute();
    }
    var obj = {
	sleep: function() {
	    task.push(_sleep.bind(null, ...arguments));
	    return obj;
        },
	eat: function() {
	    task.push(_eat.bind(null, ...arguments));
	    return obj;
	},
        sleepFirst: function() {
	    task.unshift(_sleep.bind(null, ...arguments));
	    return obj;
	}
    };
    return obj;
}
LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(10).eat('junk food');

大哥 人家说的是构建个类 不是 方法

fariellany avatar May 26 '20 07:05 fariellany

全是大佬 看不懂

fariellany avatar May 26 '20 07:05 fariellany

class LazyManClass {
  constructor(name) {
    this.name = name;
    this.taskList = [];
    this.init();
  }

  init() {
    console.log(`Hi I am ${this.name}`);
    setTimeout(() => {
      this.next();
    }, 0);
  }

  next() {
    const task = this.taskList.shift();
    task && task();
  }

  sleepFirst(interval) {
    const task = () => {
      setTimeout(() => {
        console.log(`等待了${interval}秒...`);
        this.next();
      }, interval * 1000);
    };
    this.taskList.unshift(task);
    return this;
  }

  sleep(interval) {
    const task = () => {
      setTimeout(() => {
        console.log(`等待了${interval}秒...`);
        this.next();
      }, interval * 1000);
    };
    this.taskList.push(task);
    return this;
  }

  eat(food) {
    const task = () => {
      console.log(`I am eating ${food}`);
      this.next();
    };
    this.taskList.push(task);
    return this;
  }
}

const LazyMan = (name) => new LazyManClass(name);

LazyMan('Tony').eat('apple').sleepFirst(5).sleep(3).eat('mongo');

(1)实例化对象的时候,会向setTimeout宏任务队列添加一个任务,此时script宏任务还未执完,所以不会立即执行setTimeout中的this.next()。 (2)然后执行script宏任务中的eat(),它添加了eatAppleTask到taskList的最后。
taskList = [eatAppleTask]。 (3)执行script宏任务中的sleepFirst(), 它添加了sleepFirstTask到taskList的最前面。 taskList = [sleepFirstTask,eatAppleTask]。 (4)执行script宏任务中的sleep(), 它添加了sleepTask到taskList的最后。 taskList = [sleepFirstTask,eatAppleTask,sleepTask]。 (5)执行script宏任务中的eat(),它添加了eatMongoTask到taskList的最后。 taskList = [sleepFirstTask,eatAppleTask,sleepTask,eatMongoTask]。 (6)此时script宏任务执行完毕,执行栈被清空。于是读取下一个宏任务,也就是第一步中的setTimeout,发现这个任务是可执行的(计时时间为0,早就过了)。将其回调函数提取到执行栈中执行。 (7) 于是执行回调函数this.next()。taskList中的第一个task,也就是sleepFirstTask被执行。它向setTimeout宏任务队列添加一个任务。此时执行栈中没有程序要执行,于是读取setTimeout宏任务,但是异步处理还未完成(需要3s,),所以不会提取该任务的回调函数去执行。等到3s之后,异步处理有结果了,立即将其回调提取到执行栈中执行。 (8)在sleepFirstTask中执行了this.next(),taskList中的第一个task,也就是eatAppleTask被执行。……

Wluyao avatar May 27 '20 03:05 Wluyao

function LazyMan(name) {
  const task = [];

  this.eat = (food) => {
    const fn = () => {
      console.log("I am eating", food);
      this.run();
    };
    task.push(fn);
    return this;
  };

  this.sleep = (t) => {
    const fn = () => {
      setTimeout(() => {
        console.log(`等待了${t}秒...`);
        this.run();
      }, t * 1000);
    };
    task.push(fn);
    return this;
  };

  this.sleepFirst = (t) => {
    const fn = () => {
      setTimeout(() => {
        console.log(`等待了${t}秒...`);
        this.run();
      }, t * 1000);
    };
    task.unshift(fn);
    return this;
  };

  this.run = () => {
    const fn = task.shift();
    fn && fn();
  };

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

  console.log("Hi I am", name);

  return this;
}

zhangpanfei avatar May 28 '20 05:05 zhangpanfei

看了半天发现大家都是用队列来做的吗- -

`class LazyManFactory {
  constructor(name) {
    this.name = name
    this.sayHi()
    this.sleepTime = 0
  }
  sayHi () {
    console.log(`Hi I am ${this.name}`)
  }
  sleep (time) {
    process.nextTick(() => {
      this.sleepTime += time * 1000
      setTimeout(() => console.log(`等待了${time}秒...`), this.sleepTime)
    })
    return this
  }
  eat (type) {
    process.nextTick(() => {
      setTimeout(() => {
        this.saySomething('eating', type)
      }, this.sleepTime)
    })
    return this
  }
  sleepFirst (time) {
    this.sleepTime += time * 1000
    setTimeout(() => console.log(`等待了${time}秒...`), this.sleepTime)
    return this
  }
  saySomething (action, type) {
    console.log(`I am ${action} ${type}`)
  }
}

function LazyMan (name) {
  return new LazyManFactory(name)
}

// LazyMan('Tony');
// Hi I am Tony

// LazyMan('Tony').sleep(10).eat('lunch');
// // Hi I am Tony
// // 等待了10秒...
// // I am eating lunch

// LazyMan('Tony').eat('lunch').sleep(10).eat('dinner');
// // Hi I am Tony
// // I am eating lunch
// // 等待了10秒...
// // I am eating diner

LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(10).eat('junk food');
// Hi I am Tony
// 等待了5秒...
// I am eating lunch
// I am eating dinner
// 等待了10秒...
// I am eating junk food`

xiexuan-star avatar Jun 13 '20 18:06 xiexuan-star

class LazyManClass{
    constructor(name){
        this.next = null
        this.cb = () => {}
    }

    eat(name){
        return this.delay(0, () => console.log(name))
    }

    sleep(during = 0){
        return this.delay(during)
    }

    sleepFirst(during = 0){
        return this.delay(during)
    }

    delay(during, callback){
        this.next = new LazyManClass()
        this.cb = () => setTimeout(() => {
            callback && callback()
            this.next && this.next.cb()
        }, during * 1000);
        return this.next
    }

    start(){
        setTimeout(() => this.cb(), 0);
        return this
    }
}

function LazyMan(name){
    console.log("Hi I am " + name)
    return new LazyManClass().start()
}

zhengybo avatar Jun 17 '20 16:06 zhengybo

class LazyManClass {
  constructor(name) {
    this.taskList = [];
    this.sayName(name);
    setTimeout(() => {
      this.start();
    }, 0)
  }

  eat(food) {
    this.taskList.push(() => {
      console.log(`Hi I eating ${food}`)
      const fn = this.taskList.shift();
      fn && fn();
    })
    return this;
  }

  sleep(time) {
    this.taskList.push(((time) => {
      return () => {
        setTimeout(() => {
          console.log(`等待了${time / 1000}秒`)
          const fn = this.taskList.shift();
          fn && fn();
        }, time)
      }
    })(time * 1000))
    return this;
  }

  sleepFirst(time) {
    this.taskList.unshift(((time) => {
      return () => {
        setTimeout(() => {
          console.log(`等待了${time / 1000}秒`)
          const fn = this.taskList.shift();
          fn && fn();
        }, time)
      }
    })(time * 1000))
    return this;
  }

  sayName(name) {
    console.log(`Hi I am ${name}`)
  }

  start() {
    const fn = this.taskList.shift();
    fn && fn();
  }
}

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

//LazyMan('Tony');
// Hi I am Tony

//LazyMan('Tony').sleep(10).eat('lunch');
// Hi I am Tony
// 等待了10秒...
// I am eating lunch

//LazyMan('Tony').eat('lunch').sleep(10).eat('dinner');
// Hi I am Tony
// I am eating lunch
// 等待了10秒...
// I am eating diner

LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(10).eat('junk food');
// Hi I am Tony
// 等待了5秒...
// I am eating lunch
// I am eating dinner
// 等待了10秒...
// I am eating junk food

yuanxiang1990 avatar Jul 01 '20 02:07 yuanxiang1990

class People { constructor(name) { this.name = name; this.fns = []; this.fns.push({ m: 0, fn: () => { this.print('i am ' + name); } }) setTimeout(()=>{ this.run(); }) } print(str) { console.log(str); } run(){ if(this.fns.length){ const item = this.fns.shift(); if(item.m){ item.fn(); item.fn = null; } setTimeout(()=>{ item.fn && item.fn(); this.run(); },item.m) } } eat(str){ this.fns.push({m:0,fn:()=>{ this.print(str); }}) return this; } sleep(num){ this.fns.push({ m:num, fn:()=>{ this.print('延迟了'+num+'秒。。。'); } }) return this; }

sleepFirst(num){ this.fns.splice(1,0,{ m:num, fn:()=>{ this.print('延迟了'+num+'秒。。。'); } }) return this; } } new People('phillip').eat('dinner').eat('hahaha').sleepFirst(1000).sleep(2000).eat('lunch');

wxf-start avatar Jul 11 '20 07:07 wxf-start

class LazyManClass {
    constructor(name) {
        console.log(`Hi I am ${name}`);
        this.fns = [];
        setTimeout(() => {
            this.next();
        }, 0);
    }

    eat(food) {
        this.fns.push(() => {
            console.log(`I am eating ${food}`);
            this.next();
        });
        return this;
    }

    delay(time) {
        return () => {
            setTimeout(() => {
                console.log(`等待了${time}秒...`);
                this.next();
            }, 1000 * time);
        }
    }

    sleep(time) {
        this.fns.push(this.delay(time));
        return this;
    };

    sleepFirst(time) {
        this.fns.unshift(this.delay(time));
        return this;
    };

    next() {
        this.fns.length > 0 && this.fns.shift()();
    };
}


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

hjiog avatar Jul 13 '20 05:07 hjiog

function LazyManImpl(name) {
  console.log(`Hi I am ${name}`);
  this.microQueue = [];
  this.macroQueue = [];
  this.executionContext = 'NoContext';
}
LazyManImpl.prototype.eat = function (str) {
  this.macroQueue.push(() => {
    console.log(`I am eating ${str}`);
    this.next();
  });

  this.scheduling();
  return this;
};
LazyManImpl.prototype.sleepFirst = function (number) {
  this.microQueue.push(() => {
    setTimeout(this.next.bind(this), number * 1000);
  });

  this.scheduling();
  return this;
};
LazyManImpl.prototype.sleep = function (number) {
  this.macroQueue.push(() => {
    setTimeout(this.next.bind(this), number * 1000)
  });

  this.scheduling();
  return this;
};
LazyManImpl.prototype.next = function () {
  if (this.executionContext !== 'RunContext') return;
  if (this.microQueue.length > 0) {
    const fn = this.microQueue.shift();
    fn();
  } else if (this.macroQueue.length > 0) {
    const fn = this.macroQueue.shift();
    fn();
  } else {
    this.executionContext = 'NoContext';
  }
};
LazyManImpl.prototype.scheduling = function () {
  switch (this.executionContext) {
    case 'RunContext':
      this.next();
      break;

    case 'NoContext':
      this.executionContext = 'RegisterContext';
      setTimeout(function () {
        this.executionContext = 'RunContext';
        this.next();
      }.bind(this), 0);
      break;

    case 'RegisterContext':
      break;

    default:
      // TODO warning
      break;
  }
};

const LazyMan = name => new LazyManImpl(name);

// LazyMan('Tony');
// LazyMan('Tony').sleep(10).eat('lunch');
// LazyMan('Tony').eat('lunch').sleep(10).eat('dinner');
LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(10).eat('junk food');

taichiyi avatar Jul 21 '20 06:07 taichiyi

class LazyManClass {
      constructor(name) {
        this.name = name
        this.sleepFirstAmount = 0
        this.queue = []
        Promise.resolve().then(() => {
          this.run()
        })
      }

      async run() {
        this.hello(this.name)
        if(this.sleepFirstAmount > 0) {
          await new Promise((resolve) => {
            setTimeout(resolve, this.sleepFirstAmount * 1000) 
          })
        }
        while(this.queue.length) {
          const task = this.queue.shift()
          const type = task.type
          const value = task.value
          if(type === 'eat') {
            console.log(value)
            continue
          }
          if (type === 'sleep') {
            await new Promise((resolve) => { setTimeout(resolve, value * 1000) })
          }
        }
      }

      hello(name) {
        console.log(name)
      }

      sleep(second) {
        this.queue.push({type: 'sleep', value: second})
        return this
      }

      sleepFirst(second) {
        this.sleepFirstAmount += second
        return this
      }

      eat(food) {
        this.queue.push({type: 'eat', value: food})
        return this
      }
    }

    function LazyMan(name) {
      return new LazyManClass(name)
    }

    LazyMan('Nathan').eat('apple').sleep(5).sleepFirst(3).eat('water')

NathanHan1 avatar Jul 23 '20 09:07 NathanHan1

function Man(name){
    this.name = `Hi I am ${name}`
    this.str = []
    this.time = setTimeout(()=>{
        this.parse()
    },0)
}
Man.prototype.sleep = function(minutes){
    this.str.push(`等待了${minutes}秒`)
    clearTimeout(this.time)
    this.time = setTimeout(()=>{
        this.parse()
    },0)
    return this
}
Man.prototype.eat = function(food){
    this.str.push(`I am eating ${food}`)
    clearTimeout(this.time)
    this.time = setTimeout(()=>{
        this.parse()
    },0)
    return this
}
Man.prototype.sleepFirst = function(minutes){
    this.str.unshift(`等待了${minutes}秒`)
    clearTimeout(this.time)
    this.time = setTimeout(()=>{
        this.parse()
    },0)
    return this
}
Man.prototype.parse = function(){
    console.log(this.name+'\n'+this.str.join('\n'))
}
function LazyMan(name){
    return new Man(name)
}

fengfan0409 avatar Aug 18 '20 06:08 fengfan0409