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

实现一个LazyMan #193

Open
funnycoderstar opened this issue Apr 7, 2022 · 0 comments
Open

实现一个LazyMan #193

funnycoderstar opened this issue Apr 7, 2022 · 0 comments

Comments

@funnycoderstar
Copy link
Owner

题目

实现一个LazyMan,可以按照以下方式调用:
LazyMan(“Hank”)输出:
Hi! This is Hank!

LazyMan(“Hank”).sleep(10).eat(“dinner”)输出
Hi! This is Hank!
//等待10秒..
Wake up after 10
Eat dinner~

LazyMan(“Hank”).eat(“dinner”).eat(“supper”)输出
Hi This is Hank!
Eat dinner~
Eat supper~

LazyMan(“Hank”).sleepFirst(5).eat(“supper”)输出
//等待5秒
Wake up after 5
Hi This is Hank!
Eat supper
以此类推。

实现方法一:

class LazyMan {
  constructor(name) {
    this.name = name;
    // 为什么要加 setTimeout({}, 0), 保证每轮的微任务执行后才执行,为了实现  sleepFirst 之后才执行这部分
    setTimeout(() => {
      console.log(`Hi! This is ${name}!`);
    }, 0);
  }
  eat(value) {
    // 为什么要加 setTimeout({}, 0), 保证每轮的微任务执行后才执行,为了实现  sleepFirst 之后才执行这部分
    setTimeout(() => {
      console.log(`eat ${value}`);
    }, 0);

    // 返回 this 实现链式调用
    return this;
  }

  sleep(ms) {
    const delay = ms * 1000;
    const time = Date.now();
    while (Date.now() - time < delay) {}
    // 为什么在setTimeout里返回this不行, 函数执行会先于setTimeout里面的函数执行
    setTimeout(() => {
      console.log(' sleep wake up after ' + ms);
    }, 0);

    return this;
  }

  sleepFirst(ms) {
    new Promise((resolve, reject) => {
      const delay = ms * 1000;
      const time = Date.now();
      while (Date.now() - time < delay) {}
      resolve();
    }).then(() => {
      console.log('sleepFirst wake up after ' + ms);
    });
    return this;
  }
}
function lazyMan(name) {
  return new LazyMan(name);
}
  1. 为什么必须用 setTimeout 包裹
    为了 保证每轮的微任务执行后才执行,为了实现 sleepFirst 之后才执行这部分的逻辑
  2. 在 setTimeout 里返回 this
sleep() {
const that = this;
    setTimeout(() => {
      console.log('sleep返回', that);
      return that;
    }, ms);
}

console.log('执行函数', lazyMan('Hank').sleep(10));

这种情况会出现的问题是,函数已经执行完了,才执行到 setTimeout。输出值如下

执行函数 undefined
Hi! This is Hank!
sleep返回 LazyMan { name: 'Hank' }

实现方法二

class _LazyMan {
  constructor(name) {
    this.taskQueue = [];
    this.name = name;
    this.timer = null;
    this.sayHi();
  }
  // 每次调用时清楚timer,上一次设置的执行taskQueue就不会运行。
  // 重新设置timer,会在下一次调用完后进入执行。
  // 当所有调用结束后,就会顺利执行taskQueue队列里的事件
  next() {
    clearTimeout(this.timer);
    this.timer = setTimeout(async () => {
      // 执行taskQueue队列里的事件
      for (let i = 0; i < this.taskQueue.length; i++) {
        await this.taskQueue[i]();
      }
    });
    return this;
  }
  sayHi() {
    this.taskQueue.push(() => {
      console.log('Hi! This is ' + this.name);
    });
    return this.next();
  }
  eat(str) {
    this.taskQueue.push(() => {
      console.log('Eat ' + str);
    });
    return this.next();
  }
  beforSleep(time) {
    // unshift插入到事件的第一个
    this.taskQueue.unshift(() => this.sleepPromise(time));
    return this.next();
  }
  sleep(time) {
    this.taskQueue.push(() => this.sleepPromise(time));
    return this.next();
  }
  // sleep的Promise对象,用于给async/await来阻塞后续代码执行
  sleepPromise(time) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        console.log('wake up after ' + time);
        resolve();
      }, time * 1000);
    });
  }
}

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

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

参考

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

1 participant