QuocVi1994 / Blog

frontend daily summary
8 stars 0 forks source link

[手写代码] 一个 LazyMan 是怎么养成的? #19

Open QuocVi1994 opened 3 years ago

QuocVi1994 commented 3 years ago

编程题,实现LazyMan:

• LazyMan('Hank')

• LazyMan('Hank').sleep(10).eat('dinner')

• LazyMan('Hank').eat('dinner').eat('supper')

• LazyMan('Hank').sleepFirst(5).eat('supper')

• 每个函数都返回this,供链式调用。 • this里面建立一个调用队列,在执行LazyMan时立即setTimeout(()=>顺序执行调用栈内容),确保链式调用完之后会开始执行调用栈内容。 • 根据函数的优先级去放入调用队列的前面或后面,如sleepFirst在前,sleep在后。 • 顺序执行调用栈时可被阻塞,如sleepFirst的函数执行后会返回一个Promise,然后调用栈发现是Promise则进行await,等待resolve之后才执行下一个函数。

QuocVi1994 commented 3 years ago

这是一道很经典的面试题,包括微信也曾问到过这种题目。

QuocVi1994 commented 3 years ago

class _LazyMan {
  constructor (name) {
    this.taskQueue = [];
    this.runTimer = null;
    this.sayHi(name);
  }

  run () {
    if (this.runTimer) {
      clearTimeout(this.runTimer);
    }

    this.runTimer = setTimeout(async () => {
      for (let asyncFun of this.taskQueue) {
        await asyncFun()
      }
      this.taskQueue.length = 0;
      this.runTimer = null;
    })
    return this;
  }

  sayHi (name) {
    this.taskQueue.push(async () => console.log(`Hi, this is ${name}`));
    return this.run();
  }

  eat (food) {
    this.taskQueue.push(async () => console.log(`Eat ${food}`));
    return this.run();
  }

  sleep (second) {
    this.taskQueue.push(async () => {
      console.log(`Sleep ${second} s`)
      return this._timeout(second)
    });
    return this.run();
  }

  sleepFirst (second) {
    this.taskQueue.unshift(async () => {
      console.log(`Sleep first ${second} s`)
      return this._timeout(second);
    });
    return this.run();
  }

  async _timeout (second) {
    await new Promise(resolve => {
      setTimeout(resolve, second * 1e3);
    })
  }
}

var lazyMan = name => new _LazyMan(name)

lazyMan('fucker').sleep(4).eat(`you`)