Advanced-Frontend / Daily-Interview-Question

我是依扬(木易杨),公众号「高级前端进阶」作者,每天搞定一道前端大厂面试题,祝大家天天进步,一年后会看到不一样的自己。
https://muyiy.cn/question/
27.38k stars 3.29k forks source link

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

Open zeroone001 opened 5 years ago

zeroone001 commented 5 years ago
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');
wenqingxin commented 5 years ago
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;
}
yesixuan commented 5 years ago
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 commented 5 years ago

来一个使用 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)
ppppp-x-x commented 5 years ago
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');
SpengF commented 5 years ago

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

    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')
montage-f commented 5 years ago

interface ILazyMan { name: string stack: Array

eat(food: string): any

sleep(wait: number): any

sleepFirst(wait: number): any

next()

}

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

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

GoodLuckAlien commented 5 years ago
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)
}
haojiasheng commented 5 years ago
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;
}
AChengXuYuan commented 5 years ago

用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

maginapp commented 5 years ago
 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)
 }
shuijingyue commented 5 years ago

我用了很非常简单的方法实现的,不知道是否正确,请各位朋友指正。 思路如下: 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);
yy921 commented 5 years ago
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');
JackFGreen commented 5 years ago

感觉那些 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
livetune commented 5 years ago

简单点

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,
    }
}
liuxingit commented 5 years ago

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

   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); 
            };
Aras-ax commented 5 years ago
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);
}
lvzhiyi commented 5 years ago

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

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');
HowGraceU commented 5 years ago

或许 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();
        }
    }
}
tigerdone commented 5 years ago
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)
dunhuang commented 4 years ago

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();
          }
aeolusheath commented 4 years ago

// 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里面的函数。

shenxinle commented 4 years ago
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');
youyidecai commented 4 years ago

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

Pazzilivo commented 4 years ago
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
};
ChandlerCao commented 4 years ago
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')
ChenCong6837 commented 4 years ago

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

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

yygmind commented 4 years ago
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
lemon0815 commented 4 years ago

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 commented 4 years ago

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

在 2020年1月3日,下午2:42,GelaKola notifications@github.com 写道:

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.

iceycc commented 4 years ago
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
zjiang121143210 commented 4 years ago
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');
mahuimable commented 4 years ago

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

Simmer-Jun commented 4 years ago
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');
whosesmile commented 4 years ago

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

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);
divasatanica commented 4 years ago
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 的话,无法实现执行顺序与调用顺序相同,所以就加了个新的数组,否则只用一个数组就够了

Gumplefik commented 4 years ago

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

liuyunzhuge commented 4 years ago
        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');
Murphycx94 commented 4 years ago
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')
fariellany commented 4 years ago
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 commented 4 years ago

全是大佬 看不懂

Wluyao commented 4 years ago
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被执行。……

zhangpanfei commented 4 years ago
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;
}
xiexuan-star commented 4 years ago

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

`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`
zhengybo commented 4 years ago
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()
}
yuanxiang1990 commented 4 years ago

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
wxf-start commented 4 years ago

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

hjiog commented 4 years ago
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);
}
taichiyi commented 4 years ago
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');
NathanHan1 commented 4 years ago
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')
fengfan0409 commented 4 years ago
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)
}