Sunny-117/js-challenges

实现一个 LazyMan 【字节前端面试真题】

ChelesteWang opened this issue · 7 comments

实现一个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 {
  /**
   * 构造函数
   * @param { string } name 
   */
  constructor(name) {
    this.taskQueue = []; // 任务队列
    this.sayHi(name);
    setTimeout(this._run.bind(this), 0);
  }
  /**
   * 打招呼
   * @param { string } name 
   */
  sayHi(name) {
    this.taskQueue.push(() => console.log(`Hi! This is ${name}!`));
    return this;
  }
  /**
   * 吃饭
   * @param { string } something 
   */
  eat(something) {
    this.taskQueue.push(() => console.log(`Eat ${something}~`));
    return this;
  }
  /**
   * 睡觉
   * @param { number } time 
   */
  sleep(time) {
    this.taskQueue.push(this._sleep(time));
    return this;
  }
  /**
   * 首先睡觉
   * @param { number } time 
   */
  sleepFirst(time) {
    this.taskQueue.unshift(this._sleep(time));
    return this;
  }
  /**
   * 执行任务队列
   */
  _run() {
    this.taskQueue.forEach(task => task());
  }
  /**
   * 睡觉函数
   * @param { number } time 
   */
  _sleep(time) {
    return () => {
      const start = +new Date();
      while (start + time * 1000 > +new Date());
      console.log(`Wake up after ${time}s`);
    }
  }
}

// new LazyMan("Hank").sleep(10).eat("dinner");
// new LazyMan("Hank").eat("dinner").eat("supper");
// new LazyMan("Hank").sleepFirst(5).eat("supper");
let _LazyMan = function (name) {
    this.taskQueue = []
    let that = this
    // 全部push完成之后,开始执行微任务队列
    // Promise.resolve().then(() => {
    //     // 将要执行的任务,全部丢进微任务队列执行
    //     let p = Promise.resolve()
    //     that.taskQueue.map(t => {
    //         p = p.then(t)
    //     })
    // })
    setTimeout(() => {
        that.taskQueue.map(async t => {
            await t()
        })
    })
}

_LazyMan.prototype.hold = function (time) {
    this.taskQueue.push(() => {
        return new Promise((resolve, reject) => {
            console.log(`sleep start`)
            setTimeout(() => {
                console.log(`sleep end`)
                resolve()
            }, time * 1000)
        })
    })
}

_LazyMan.prototype.sleep = function (time) {
    this.hold(time)
    return this
}

_LazyMan.prototype.sayHello = function (name) {
    this.taskQueue.push(() => {
        console.log(`hello ${name}`)
    })
    return this
}

let LazyMan = (name) => new _LazyMan(name)

LazyMan('yedi')
    .sleep(1)
    .sayHello("yedi")
    .sleep(5)
    .sayHello("h")
class LazyMan {
  constructor(name) {
    this.name = name;
    this.queue = [];
    console.log(`Hi this is ${this.name}`);
    setTimeout(() => {
      this.next();
    });
  }
  eat(arg) {
    const task = () => {
      console.log(`eat ${arg}`);
      this.next();
    };
    this.queue.push(task);
    return this;
  }
  next() {
    const task = this.queue.shift();
    task && task();
  }
  _sleep(time, isFirst) {
    const task = () => {
      console.log("sleep start");
      setTimeout(() => {
        console.log("sleep end");
        this.next();
      }, time * 1000);
    };
    if (isFirst) {
      this.queue.unshift(task);
    } else {
      this.queue.push(task);
    }
    return this;
  }
  sleep(time) {
    this._sleep(time, false);
    return this;
  }
  sleepFirst(time) {
    this._sleep(time, true);
    return this;
  }
}
const lazyMan = new LazyMan("张三");
lazyMan.eat("dinner").sleep(10).eat("super").sleep(5);
class LLazyMan {
  constructor(name) {
    this.name = name;
    this.queue = [];
    this.sayName();
    this.run();
  }
  sayName() {
    this.queue.push(() => {
      console.log(`Hi! This is ${this.name}`);
    });
    return this;
  }
  sleep(time) {
    this.queue.push(() => this.timeWait(time));
    return this;
  }
  sleepFirst(time) {
    this.queue.unshift(() => this.timeWait(time));
    return this;
  }
  timeWait(time) {
    return new Promise((resolve) =>
      setTimeout(() => {
        console.log(`Wake up after ${time}`);
        resolve();
      }, time * 1000)
    );
  }
  eat(param) {
    this.queue.push(() => {
      console.log(`Eat ${param}`);
    });
    return this;
  }
  run() {
    setTimeout(async () => {
      for (const task of this.queue) {
        await task();
      }
    }, 0);
  }
}
const LazyMan = (name) => new LLazyMan(name);
// LazyMan("Hank").sleepFirst(5).eat("supper");
// LazyMan("Hank").eat("dinner").eat("supper");
LazyMan("c2c").sleep(2).eat("s");
class LazyManClass {
  constructor(name) {
    this.tasks = [];
    this.name = name;
    this.sayHi();
    this._run();
  }

  sayHi(){
    this.tasks.push(()=>console.log(`Hi!this is ${this.name}`))
    return this
  }

  sleep(ms) {
    this.tasks.push(() => this.sleepFn(ms));
    return this;
  }

  eat(name) {
    this.tasks.push(() => console.log(`Eat ${name}`))
    return this;
  }

  sleepFirst(ms) {
    this.tasks.unshift(() => this.sleepFn(ms));
    return this;
  }

  sleepFn(time) {
    return new Promise((resolve) =>
      setTimeout(() => {
        console.log(`Wake up after ${time}`);
        resolve();
      }, time * 1000)
    );
  }

  _run(){
    // setTimeout(()=>{
    //   this.tasks.forEach(async task => await task())
    // },0)

    setTimeout(async ()=>{
      for (const task of this.tasks) {
        await task();
      }
    },0)
  }
}

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

LazyMan("Hank").sleep(10).eat("dinner");

为什么forEach中用async并不能阻塞后面任务执行,用for of遍历时是可以的啊

class Lazy {
    constructor(str) {
        this.taskQueue = [{
            msg: `Hi This is ${str}`,
            sleep: 0
        }]
        this.sleepTime = 0
        Promise.resolve().then(() => {
            this._run()
        })
    }
    sleep(t) {
        this.sleepTime = t
        return this
    }
    eat(str) {
        const obj = {
            msg: `Eat ${str}`,
            sleep: this.sleepTime
        }
        this.sleepTime = 0
        this.taskQueue.push(obj)
        return this
    }
    sleepFirst(t) {
        this.taskQueue[0].sleep = t
        return this
    }
    _run() {
        const delay = (time) => {
            return new Promise(resovle => {
                setTimeout(() => {
                    resovle()
                }, time);
            })
        }
        const _call = async () => {
            for (const task of this.taskQueue) {
                if (task.sleep) {
                    console.log(`Wake up after ${task.sleep}`)
                    await delay(task.sleep * 1000)
                }
                console.log(task.msg)
            }
        }
        _call()
    }
}

function LazyMan(str) {
    return new Lazy(str)
}

LazyMan('gsw').sleepFirst(5).sleep(3).eat('dzq').sleep(4).eat('ysy').sleep(3).eat('zbc')
`实现一个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
以此类推。`;

function LazyMan(name) {
  const hi = async () => {
    console.log("Hi This is " + name + "!");
  };
  const Tasks = [hi];

  const eat = (value) => {
    const eatHandle = async () => {
      console.log("Eat" + value + "~");
    };
    Tasks.push(eatHandle);
    return obj;
  };
  const sleepFirst = (value) => {
    const sleepFirstHandle = async () => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          console.log("Wake up after " + value);
          resolve();
        }, value * 1000);
      });
    };
    Tasks.unshift(sleepFirstHandle);
    return obj;
  };
  const sleep = (value) => {
    const sleepHandle = async () => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          console.log("Wake up after " + value);
          resolve();
        }, value * 1000);
      });
    };
    Tasks.push(sleepHandle);
    return obj;
  };
  let obj = {
    eat,
    sleepFirst,
    sleep,
  };
  setTimeout(async () => {
    for await (const task of Tasks) {
      await task();
    }
  }, 0);
  return obj;
}

LazyMan("Hank").sleepFirst(5).eat("supper").sleep(2).eat("鱼");