Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
zeroone001 opened this issue Apr 16, 2019 · 137 comments
Open

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

zeroone001 opened this issue Apr 16, 2019 · 137 comments

Comments

@zeroone001
Copy link

zeroone001 commented Apr 16, 2019

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');
@lvwxx
Copy link

lvwxx commented Apr 17, 2019

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)
}

@csm0912
Copy link

csm0912 commented Apr 17, 2019

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()();
    };
}

@jefferyE
Copy link

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')

@Yanhua67
Copy link

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');

@mengsixing
Copy link

mengsixing commented Apr 17, 2019

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

@happywanghao
Copy link

    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;
        }
      };
    };

@BaconZhang
Copy link

写个链表实现

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');

@Seasonley
Copy link

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)
}

@lulusir
Copy link

lulusir commented Apr 17, 2019

/**
 * 普通 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()

@Banlangenn
Copy link

Banlangenn commented Apr 17, 2019

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

@yiqingfeng
Copy link

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;
}

@Mistyyyy
Copy link

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');

@zhuzhh
Copy link

zhuzhh commented Apr 17, 2019

// 写一个 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)
}   

@neofanfei
Copy link

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_

@yeyan1996
Copy link

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()
        }
    }
}

@jayPiece
Copy link

    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写了一遍

@twosugar
Copy link

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

@jayPiece
Copy link

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

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

@twosugar
Copy link

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

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

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

@RichardPear
Copy link

RichardPear commented Apr 20, 2019

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');

@lzbSun
Copy link

lzbSun commented Apr 22, 2019

有大佬能解答下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
Copy link

lzbSun commented Apr 22, 2019

@GuidingStarKe

@twosugar
Copy link

有大佬能解答下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

首先谢谢解答和分享!

@bohaixv
Copy link

bohaixv commented Apr 24, 2019

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');

@pengcc
Copy link

pengcc commented Apr 26, 2019

用了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);
        }
    }
}

@kangkai124
Copy link

image

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

@zhuzhh
Copy link

zhuzhh commented Apr 30, 2019 via email

@YagamiNewLight
Copy link

YagamiNewLight commented May 6, 2019

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 )效果一样了

@liujuntao123
Copy link

liujuntao123 commented May 30, 2019

不用类的实现,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()()
  }
}

@dguoqing
Copy link

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')

@lizhiyao
Copy link

lizhiyao commented Dec 13, 2020

/**
 * 考察点
 * 1. 实现函数的链式调用
 * 2. 宏任务 vs 微任务
 * 3. 数据结构的应用(基于数组模拟链表)
 */
class LazyManClass {
  constructor(name) {
    this.name = name;
    this.tasks = []; // 将所有链式调用的函数放入到一个队列中,通过调用 next 方法执行函数队列中下一个函数

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

    // 在类被实例化时,会开启一个宏任务。实例化及后续的同步链式函数调用均在同一个宏任务中
    // 通过 setTimeout 新增一个宏任务,保证首次执行函数执行队列中的函数是在链式调用结束后开始
    setTimeout(() => {
      this.next();
    }, 0);
    // 也可以使用 Promise 代替此处 setTimeout 实现
    // Promise.resolve().then(() => {
    //   this.next();
    // });
  }

  // 执行函数队列中下一个函数
  next() {
    const fn = this.tasks.shift();
    fn && fn();
  }

  eat(food) {
    this.tasks.push(() => {
      console.log(`I am eating ${food}`);
      this.next();
    });
    return this; // 每一个链式调用的函数需要返回 this,确保队列中后续函数可以执行
  }

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

  sleep(time) {
    this.tasks.push(() => {
      this._sleep(time);
    });
    return this;
  }

  sleepFirst(time) {
    // 通过 unshift 将函数添加到函数队列的开头
    this.tasks.unshift(() => {
      this._sleep(time);
    });
    return this;
  }
}

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

@pan-Z2l0aHVi
Copy link

1、回调嵌套实现

class LazyManClass {
  constructor(name) {
    this.name = name
    this.tasks = []

    console.log('Hi I am Tony')
    setTimeout(() => {
      this.next()
    }, 0)
  }

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

  sleep(duration) {
    this.tasks.push(() => this._doSleep(duration))
    return this
  }

  sleepFirst(duration) {
    this.tasks.unshift(() => this._doSleep(duration))
    return this
  }

  _doSleep(duration) {
    setTimeout(() => {
      console.log(`等待了${duration}秒`)
      this.next()
    }, duration * 1000)
  }

  next() {
    if (this.tasks.length) {
      const task = this.tasks.shift()
      task()
    }
  }
}
function LazyMan(name) {
  return new LazyManClass(name)
}

2、promise 迭代实现

class LazyManClass {
  constructor(name) {
    this.name = name
    this.tasks = []
    console.log('Hi I am Tony')
    setTimeout(() => {
      this._interate()
    }, 0)
  }

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

  sleep(duration) {
    this.tasks.push(() => this._doSleep(duration))
    return this
  }

  sleepFirst(duration) {
    this.tasks.unshift(() => this._doSleep(duration))
    return this
  }

  _doSleep(duration) {
    return new Promise((resolve) => {
      setTimeout(() => {
        console.log(`等待了${duration}秒`)
        resolve()
      }, duration * 1000)
    })
  }

  async _interate() {
    // 用 for of 也行
    for await (const task of this.tasks) {
      await task()
    }
  }
}

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

测试

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

@xjiabin
Copy link

xjiabin commented Feb 3, 2021

image

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

可以这样用,task 箭头函数不接受参数,直接用外部 eat 方法的参数

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

@livetune
Copy link

livetune commented Feb 3, 2021

class LazyManClass {
  constructor(name) {
    console.log(`Hi I am ${name}`)
    setTimeout(async () => {
      for (const fn of this.task) {
        console.log(await fn())
      }
    })
  }
  task = []
  timeOut(time, isFirst = false) {
    this.task[isFirst ? 'unshift' : "push"](
      async () => new Promise(r =>
        setTimeout(() => r(`等待了${time}秒...`), time)
      )
    )
    return this
  }
  sleep(time) {
    return this.timeOut(time)
  }
  sleepFirst(time) {
    return this.timeOut(time, true)
  }
  eat(food) {
    this.task.push(async () => Promise.resolve(`I am eating ${food}`))
    return this
  }
}
const LazyMan = (name) => new LazyManClass(name)
LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(10).eat('junk food');

@Yayure
Copy link

Yayure commented Mar 11, 2021

for await of+async iterable方式:

function LazyMan(name) {
  let ins = Object.create({
    sleep: function(time) {
      this.stack.push({ log: `等待了${time}秒`, time });
      return this
    },
    eat: function(food) {
      this.stack.push({ log: `I am eating ${food}` });
      return this
    },
    sleepFirst: function(time) {
      this.stack.splice(1, 0, { log: `等待了${time}秒`, time });
      return this
    }
  });
  ins.stack = [];
  ins.stack.push({ log: `Hi I am ${name}` });
  (async function(stack) {
    const stackGen = function*() {
      for (let i = 0; i < stack.length; i++) {
        yield new Promise((resolve, reject) => {
          let { log, time = 0 } = stack[i];
          setTimeout(() => {
            resolve(log);
          }, time * 1000);
        });
      }
    }
    for await (let log of stackGen()) {
      console.log(log);
    };
  })(ins.stack);
  return ins;
}

递归方式:

function LazyMan(name) {
  let ins = Object.create({
    sleep: function(time) {
      this.stack.push({ log: `等待了${time}秒`, time });
      return this
    },
    eat: function(food) {
      this.stack.push({ log: `I am eating ${food}` });
      return this
    },
    sleepFirst: function(time) {
      this.stack.splice(1, 0, { log: `等待了${time}秒`, time });
      return this
    }
  });
  ins.stack = [];
  ins.stack.push({ log: `Hi I am ${name}` });
  Promise.resolve().then(() => {
    (function recursionExec(stack) {
      let { log, time = 0 } = stack.shift();
      new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve(log);
        }, time * 1000);
      }).then((log) => {
        console.log(log);
        if (stack.length != 0) {
          recursionExec(stack);
        }
      });
    })(ins.stack);
  });
  return ins;
}

@Yang-Bkfjn
Copy link

image

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

image

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

应该是闭包 保存变量 吧

@peterczg
Copy link

peterczg commented May 4, 2021

function LazyMan(name) {
  return new (class LazyMan {
    constructor() {
      this.name = name;
      console.log(`Hi I am ${name}`);
      this.taskList = [];
      setTimeout(async () => {
        for (const cb of this.taskList) {
          await cb();
        }
      }, 0);
    }

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

    sleep(sec, isFirst = false) {
      const method = isFirst ? "unshift" : "push";
      this.taskList[method](
        async () =>
          await new Promise((resolve) => {
            setTimeout(() => {
              console.log(`wait for ${sec} seconds`);
              resolve();
            }, sec * 1000);
          })
      );
      return this;
    }

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

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

@zhelingwang
Copy link

function LazyMan(name) {
      console.log(`Hi I am ${name}`);
      const _obj = {
        callback: [],
        pushCallback(cb, unshift = false) {
          if (unshift) return this.callback.unshift(cb);
          this.callback.push(cb);
        },

        _init() {
          setTimeout(() => {
            let idx = 0, self = this;
            function _inner(idx) {
              new Promise(async (resolve, reject) => {
                const callback = self.callback[idx];
                await callback();
                resolve();
              }).then(() => {
                idx++;
                if (idx < self.callback.length) {
                  _inner(idx);
                }
              });
            }
            _inner(idx);
          }, 0);
        },

        eat(eatTime) {
          this.pushCallback(() => {
            console.log(`I am eating ${eatTime}`);
          },
          );
          return this;
        },
        sleep(delay) {
          this.pushCallback(() => {
            return new Promise((resolve, reject) => {
              console.log(`要等待${delay}秒...`);
              setTimeout(() => {
                resolve();
              }, delay * 1000)
            })
          },
          );
          return this;
        },
        sleepFirst(delay) {
          this.pushCallback(() => {
            return new Promise((resolve, reject) => {
              console.log(`要等待${delay}秒...`);
              setTimeout(() => {
                resolve();
              }, delay * 1000)
            })
          }, true);
          return this;
        }
      };
      _obj._init();
      return _obj;
    }

@MrLeihe
Copy link

MrLeihe commented May 10, 2021

类似于消息队列一样,排队取出任务执行,sleepFirst 就像是优先级更高的任务

function LazyManClass(name) {
  this.name = name
  this.queue = []
  console.log(`Hi I am ${name}`)
  Promise.resolve().then(() => {
    this.next()
  })
}

LazyManClass.prototype.eat = function (eatName) {
  this.queue.push(() => {
    console.log(`I am eating ${eatName}`)
    this.next()
  })
  return this
}

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

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

LazyManClass.prototype.next = function () {
  var task = this.queue.shift()
  task && task()
}

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

@13866368297
Copy link

13866368297 commented Jul 20, 2021

   //函数式写法

   
   function LazyMan(name) {

        const createMan = (name) => {
            console.log(`Hi I am ${name}`);
            let queue = []

            let pending = true
            const run = () => {
                if (!pending) return
                pending = false
                Promise.resolve().then(() => {
                    queue.reduce((promise, fn) => {
                        return promise.then(fn)
                    }, Promise.resolve())
                })
            }

            const wrap = (action, instance,first) => {
                return (...args) => {
                    const fn = () => action(...args)
                    first ? queue.unshift(fn) : queue.push(fn)
                    run()
                    return instance
                }
            }
            const eat = (meal) => {
                console.log(`I am eating ${meal}`);
            }
            const sleep = (time) => {
                return new Promise(resolve=>{
                    setTimeout(()=>{
                        console.log(`等待了${time}秒...`);
                        resolve()
                    },time*1000)
                })
            }

            const instance = {
                eat: null,
                sleep: null,
            }
            instance.eat = wrap(eat, instance)
            instance.sleep = wrap(sleep, instance)
            instance.sleepFirst = wrap(sleep, instance, true)
            return instance
        }

        const instance = createMan(name)
        return instance
    }

@mygod48
Copy link

mygod48 commented Oct 27, 2021

构造函数中加入开始执行任务队列的语句会导致延迟添加的任务无法执行,例如:

const lazyMan = LazyMan('name');
setTimeout(() => {
    lazyMan.eat('lunch');
}, 200)

以下是我的解决方法,将setTimeout封装进“添加任务”的函数中以实现延迟执行

class LazyManClass {
    constructor (name) {
        this.name = name;
        console.log(`Hi I am ${name}`);

        this.taskQueue = [];
        this.activeTimer = 0;
    }

    static getHaveMealTask (meal) {
        return () => { console.log(`I am eating ${meal}`); }
    }

    static getSleepTask (seconds) {
        return () => {
            console.log(`等待${seconds}秒...`)
            return new Promise((resolve) => {
                setTimeout(() => {
                    resolve()
                }, seconds * 1000)
            })
        }
    }

    async activeTasks () {
        let task = null;
        while (task = this.taskQueue.pop()) {
            await task();
        }
    }

    enqueueTask (task, index = 0) {
        if (index === 0) {
            this.taskQueue.unshift(task);
        } else if (index === 'head') {
            this.taskQueue.push(task);
        } else {
            this.taskQueue.splice(index, 0, task);
        }
        
        clearTimeout(this.activeTimer);
        this.activeTimer = setTimeout(() => {
            this.activeTasks();
        });
    }

    eat (meal) {
        this.enqueueTask(LazyManClass.getHaveMealTask(meal));
        return this;
    }

    sleep (seconds) {
        this.enqueueTask(LazyManClass.getSleepTask(seconds));
        return this;
    }

    sleepFirst (seconds) {
        this.enqueueTask(LazyManClass.getSleepTask(seconds), 'head');
        return this;
    }
}

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

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

@xiaobc1234
Copy link

xiaobc1234 commented Dec 2, 2021

用防抖来解:


const stop = (s = 0) => {
    return new Promise(resolve => {
        setTimeout(resolve, s * 1000 );
    })
}

class LazyMan {

    constructor(name) {
        console.log('Hi I am ' + name);
        this.queue = [];
        this.timer = null;
    }

    debounce() {
        if(this.timer) {
            clearTimeout(this.timer);
            this.timer = null;
        }
        this.timer = setTimeout(() => {
            this.handleQueue();
            this.timer = null;
        }, 10);
    }

    sleep(s) {
        this.debounce();
        this.queue.push(async () => {
            await stop(s);
            console.log(`等待了${s}秒...`);
        });
        return this;
    }

    sleepFirst(s) {
        this.debounce();
        this.queue.unshift(async () => {
            await stop(s);
            console.log(`等待了${s}秒...`);
        });
        return this;
    }

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

    async handleQueue() {
        while(this.queue.length > 0) {
            const run = this.queue.shift();
            await run();
        }
    }

}

@WebXiaoMing
Copy link

function LazyMan(name) {
  console.log(`Hi I am ${name}`)
  let next = Promise.resolve()

  this.sleep = function(time) {
    Promise.resolve().then(() => {
      next = next.then(() => new Promise(resolve => setTimeout(resolve, time * 1000)))
    })
    return this
  }

  this.eat = function(name) {
    Promise.resolve().then(() => {
      next = next.then(() => new Promise(resolve => {
        console.log(`I am eating ${name}`)
        resolve()
      }))
    })
    return this
  }

  this.sleepFirst = function(time) {
    next = new Promise(resolve => setTimeout(resolve, time * 1000))
    return this
  }
  return this
}

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

@CHristopherkeith
Copy link

class LazyManClass {
  constructor(name) {
    this.name = name;
    this.queue = [];
    this.sayName();
    setTimeout(() => {
      this.doSth();
    }, 0);
  }
  sayName() {
    console.log(`Hi I am ${this.name}`);
  }
  eat(food) {
    this.queue.push({ action: "doEat", sth: food });
    return this;
  }
  doEat(food) {
    console.log(`I am eating ${food}`);
  }
  sleep(time) {
    this.queue.push({ action: "doSleep", sth: time });
    return this;
  }
  sleepFirst(time) {
    this.queue.unshift({ action: "doSleep", sth: time });
    return this;
  }
  doSleep(time) {
    setTimeout(() => {
      console.log(`${time} sencond later...`);
      this.doSth();
    }, time * 1000);
  }
  doSth() {
    while (this.queue.length) {
      const { action, sth } = this.queue.shift();
      this[action](sth);
      if (action === "doSleep") {
        break;
      }
    }
  }
}
const LazyMan = function (name) {
  return new LazyManClass(name);
};

export default LazyMan;

@IveChen
Copy link

IveChen commented Feb 11, 2022 via email

@susancolour
Copy link

susancolour commented Feb 11, 2022 via email

@JonathonChen
Copy link

JonathonChen commented Feb 11, 2022 via email

@Four-Names
Copy link

function LazyMan(name) {
  this.name = name;
  this.task = [];

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

  setTimeout(async () => {
    while (this.task.length) await this.task.shift()();
  }, 4);

  this.eat = function (food) {
    this.task.push(console.log.bind(this, `I am eating ${food}`));
    return this;
  };

  this.sleepFirst = function (timeout) {
    this.task.splice(0, 0, async () => {
      return new Promise((resolve) => setTimeout(resolve, timeout * 1000));
    });
    return this;
  };

  this.sleep = function (timeout) {
    this.task.push(async () => {
      return new Promise((resolve) => setTimeout(resolve, timeout * 1000));
    });
    return this;
  };

  return this;
}

@luoguoxiong
Copy link

class LazyManClass {
  constructor(name) {
    this.taskList = [];
    this.name = name;
    console.log(`Hi I am ${this.name}`);
    Promise.resolve().then(async() => {
      await this.next();
    });
  }
  eat(name) {
    this.taskList.push(() => new Promise((resolve) => {
      console.log(`eat${name}`);
      resolve();
    }));
    return this;
  }
  sleepFirst(time) {
    this.taskList.unshift(() => new Promise((resolve) => {
      setTimeout(() => {
        console.log(`等待了${time}秒...`);
        resolve();
      }, time * 1000);
    }));
    return this;
  }
  sleep(time) {
    this.taskList.push(() => new Promise((resolve) => {
      setTimeout(() => {
        console.log(`等待了${time}秒...`);
        resolve();
      }, time * 1000);
    }));
    return this;
  }
  async next() {
    while(this.taskList.length){
      await this.taskList.shift()();
    }
  }
}
function LazyMan(name) {
  return new LazyManClass(name);
}
LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(4).eat('junk food');

@ACE-LV
Copy link

ACE-LV commented Mar 26, 2022

function lazyMan(name) {
class LazyMan {
constructor(name) {
this.name = name;
this._queues = [];
console.log(Hi I am ${name});
setTimeout(() => {
this.next();
}, 0);
}
sleep(t) {
const fn = (() => {
return async () => {
console.log(等待了${t}s);
this.next();
};
})(t);
this._queues.push(fn);
return this;
}
eat(food) {
const fn = (() => {
return async () => {
console.log(I am eating${food});
this.next();
};
})(food);
this._queues.push(fn);
return this;
}
sleepFirst(t) {
const fn = (() => {
return async () => {
console.log(等待了${t}s);
this.next();
};
})(t);
this._queues.unshift(fn);
return this;
}
next() {
const fn = this._queues.shift();
fn && fn();
}
}

return new LazyMan(name);

}

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

@espory
Copy link

espory commented Mar 31, 2022

class LazyMan{
  constructor(name){
    this.name = name;
    this.tasks = [];
    //宏任务延时执行
    setTimeout(()=>{
      this.start();
    },0)
  }
  sleep(time){
    this.tasks.push(()=>{
      return new Promise((resolve)=>{
        setTimeout(()=>{
          console.log('等待了几秒')
            resolve()
        },time*1000)
      })
    })
    return this;
  }

  eat(param){
      this.tasks.push(()=>{
        console.log(`eat ${param}`);
      })
      return this;
  }
  sleepFirst(time){
     this.tasks.unshift(()=>{
      return new Promise((resolve)=>{
        setTimeout(()=>{
          console.log('first 等待了几秒')
            resolve()
        },time*1000)
      })
    })
    return this;
  }
  async start(){
    for(let task of this.tasks){
      await task();
    }
  }
}

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

@miniflycn
Copy link

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

class Man {
    constructor(name) {
        this.tasks = []
        console.log(`Hi I am ${name}`)
        this.run()
    }
    createTask(word, time = 0) {
        let task
        if (time) {
            task = () => {
                setTimeout(() => {
                    word && console.log(word)
                    this.next()
                }, time * 1000)
            }
        } else {
            task = () => {
                console.log(word)
                this.next()
            }
        }
        return task
    }
    eat(food) {
        this.tasks.push(this.createTask(`I am eating ${food}`))
        return this
    }
    sleepFirst(time) {
        this.tasks.unshift((this.createTask(undefined, time)))
        return this
    }
    sleep(time) {
        this.tasks.push(this.createTask(undefined, time))
        return this
    }
    next() {
        if (this.tasks.length) {
            this.tasks.shift()()
        }
    }
    run() {
        setTimeout(() => {
            this.next()
        }, 0)
    }
}

@ShopkeeperEgg
Copy link


function sleep (s) {
  return new Promise(res => {
    setTimeout(() => {
      res(1);
    }, s * 1000);
  })
}

class LazyManCons {
  taskQueue = [];
  running = false;
  constructor(name) {
    console.log(`Hi I am ${name}`);
  }
  
  eat(food) {
    this.taskQueue.push(['eat', food])
    Promise.resolve().then(() => this.runTask());
    return this;
  }
  
  
  sleep(s) {
    this.taskQueue.push(['sleep', s])
    Promise.resolve().then(() => this.runTask());
    return this;
  }


  firstSleep(s) {
    this.taskQueue.push(['sleep', s])
    Promise.resolve().then(() => this.runTask());
    return this;
  }
  
  
  async runTask() {
    if (this.running) return;
    this.running = true;
    while (this.taskQueue.length) {
      const [task, taskDetail] = this.taskQueue.shift();
      if (task === 'eat') {
        console.log(`I am eating ${taskDetail}`);
      }
      if (task === 'sleep') {
        await sleep(taskDetail);
      }
    }
    this.running = false;
  }
}


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

@wumo1016
Copy link

wumo1016 commented Sep 20, 2022

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

@xgqfrms
Copy link

xgqfrms commented Oct 20, 2022

flag version

// flag
class Chain {
  constructor() {
    this.flag = true;
    this.time = 0;
  }
  eat(name = ``) {
    if(!this.flag) {
      setTimeout(() => {
        log(`eat =`, name);
      }, this.time);
    } else {
      log(`eat =`, name);
    }
    return this;
  }
  work(name = ``) {
    if(!this.flag) {
      setTimeout(() => {
        log(`work =`, name);
      }, this.time);
    } else {
      log(`work =`, name);
    }
    return this;
  }
  sleep(time = 0) {
    this.flag = false;
    this.time = 1000 * time;
    let that = this;
    setTimeout(() => {
      log(`\nsleep =`, time);
      that.flag = true;
      that.time = 0;
    }, 1000 * time);
    return that;
  }
}

const chain = new Chain();

chain
.eat('apple')
.sleep(3)
.eat('orange')
.sleep(6)
.work('programming');

@xuxin666666
Copy link

class Man {
    constructor(name) {
        console.log(`Hi I am ${name}`)
        this.first = []
        this.rest = []

        setTimeout(() => {
            this.start()
        })
    }
    eat(food) {
        this.rest.push(() => Promise.resolve(console.log(`I am eating ${food}`)))

        return this
    }
    sleep(time) {
        this.rest.push(() => new Promise((resolve) => {
            setTimeout(() => {
                console.log(`等待了${time}秒...`)
                resolve()
            }, time * 1000)
        }))
        return this
    }
    sleepFirst(time) {
        this.first.push(() => new Promise((resolve) => {
            setTimeout(() => {
                console.log(`等待了${time}秒...`)
                resolve()
            }, time * 1000)
        }))

        return this
    }
    async start() {
        for(let item of this.first) {
            await item()
        }
        for(let item of this.rest) {
            await item()
        }
    }
}

function LazyMan(name) {
    let man = new Man(name)

    return man
}

@JDEast1029
Copy link

JDEast1029 commented Nov 5, 2022

const LazyMan = (name) => {
  console.log(`Hi I am ${name}`);
  let queue = [];
  let timer = null;
  return {
    dequeue() {
      timer && clearTimeout(timer);
      timer = setTimeout(() => {
        while (queue.length) {
          const cb = queue.shift();
          cb();
        }
      }, 0);
    },
    enqueue(cb, head = false) {
      head ? queue.unshift(cb) : queue.push(cb);
      this.dequeue();
      return this;
    },
    eat(type) {
      return this.enqueue(() => {
        console.log(`I am eating ${type}`);
      });
    },
    sleepCore(time) {
      console.log(`等待${time}秒...`);
      const start = new Date().getTime();
      while (new Date().getTime() - start <= time * 1000) {}
    },
    sleep(time) {
      return this.enqueue(() => {
        this.sleepCore(time);
      });
    },
    sleepFirst(time) {
      return this.enqueue(() => {
        this.sleepCore(time);
      }, true);
    },
  };
};

@leishuimiao
Copy link

function LazyMan(name) {
  console.log(`Hi I am ${name}`)
  // 回调队列
  const queues = []
  let status = 'immediate' // 立刻执行

  this.sleep = (seconds, length) => {
    if (status === 'pendingFirst') {
      status = 'padding' // 立即等待
    } else {
      setTimeout(() => {
        status = 'pending' // 延迟等待
      }, 0)
    }
    setTimeout(() => {
      console.log(`等待了${seconds}秒...`)
      Array.from({ length: length || queues.length }).forEach(() => {
        // 先进先出
        queues.shift()()
      })
      status = 'immediate'
    }, seconds * 1000)
    return this
  }

  this.sleepFirst = (seconds) => {
    status = 'pendingFirst' // 优先等待
    return this.sleep(seconds, queues.length)
  }

  this.eat = (foodName) => {
    queues.push(() => {
      console.log(`I am eating ${foodName}`)
    })
    // 延时执行,保证status是被执行函数修改后的状态
    setTimeout(() => {
      if (status === 'immediate') queues.shift()()
    }, 0)
    return this
  }
  return this
}

@RaindropSaber
Copy link

RaindropSaber commented Nov 9, 2023

class LazyMan {
  constructor(name) {
    console.log(`Hi I am ${name}`);
    this.next = new Promise((_r) => (this.start = _r));
    Promise.resolve().then(() => this.start());
  }
  eat(str) {
    this.next = this.next.then(() => console.log(`I am eating ${str}`));
    return this;
  }
  sleep(t) {
    this.next = this.next
      .then(() => new Promise((r) => setTimeout(r, t * 1000)))
      .then(() => console.log(`sleep ${t} s`));
    return this;
  }
  sleepFirst(t) {
    const oldNext = this.next;
    const oldStart = this.start;
    this.next = new Promise((_r) => (this.start = _r))
      .then(() => new Promise((r) => setTimeout(r, t * 1000)))
      .then(() => console.log(`sleepFirst ${t} s`))
      .then(() => oldStart())
      .then(() => oldNext);

    return this;
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests