V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
xiaoming1992
V2EX  ›  JavaScript

一道字节面试题解

  •  1
     
  •   xiaoming1992 · 2020-06-01 21:35:24 +08:00 · 1907 次点击
    这是一个创建于 1672 天前的主题,其中的信息可能已经有所发展或是发生改变。

    刚刚面了字节跳动, 题目都很(~~~~~~)基础, 但就是答得不好...视频一挂, 诶, 有好想法了 T.T

    不行, 我非得把答案贴这儿, 可惜面试官不在我面前, 不然我非得告诉他, 你看, 这解答至少还凑合啊

    // 题目是实现下列链式调用
    const chain = new Chain()
    
    chain
      .eat()
      .sleep(1000)
      .eat()
      .sleep(1000)
      .work()
    
    // 我原来用的 promise 把所有方法都包裹起来, 简直丑破天际...
    // 下面是新的解答
    // 至于里面有些属性是不是要用 private 或者 protected 什么的, 我就懒得细究了
    
    interface EatAction {
      name: "eat";
      params: [];
    }
    
    interface SleepAction {
      name: "sleep";
      params: [number];
    }
    
    interface WorkAction {
      name: "work";
      params: [];
    }
    
    type Action = EatAction | SleepAction | WorkAction
    
    class Chain {
      running = false
    
      actions: Action[] = []
    
      trigger() {
        if (this.running) { return }
        const action = this.actions.shift()
        if (!action) { return }
    
        this.running = true
    
        switch (action.name) {
        case "eat":
          console.log("eat")
          this.running = false
          this.trigger()
          break
        case "work":
          console.log("work")
          this.running = false
          this.trigger()
          break
        case "sleep":
          setTimeout(() => {
            console.log("sleep")
            this.running = false
            this.trigger()
          }, action.params[0])
          break
        default:
          break
        }
      }
    
      eat() {
        this.actions.push({
          name: "eat",
          params: [],
        })
        this.trigger()
        return this
      }
    
      sleep(n: number) {
        this.actions.push({
          name: "sleep",
          params: [n],
        })
        this.trigger()
        return this
      }
    
      work() {
        this.actions.push({
          name: "work",
          params: [],
        })
        this.trigger()
        return this
      }
    }
    
    jason94
        1
    jason94  
       2020-06-01 22:15:25 +08:00
    这样是不是简单一点

    ```ts
    class Chain {
    private actions: Function[] = [];
    constructor() {
    setTimeout(async () => {
    for (const action of this.actions) {
    await action.call(this);
    }
    });
    }

    eat() {
    this.actions.push(() => console.log('eat'));

    return this;
    }

    sleep(timeout: number) {
    this.actions.push(() => {
    console.log('sleep ', timeout);
    return new Promise((resolve) =>
    setTimeout(() => {
    resolve();
    }, timeout)
    );
    });
    return this;
    }
    work() {
    this.actions.push(() => console.log('work'));

    return this;
    }
    }

    const chain = new Chain();

    chain.eat().sleep(1000).eat().sleep(1000).work();

    ```
    xiaoming1992
        2
    xiaoming1992  
    OP
       2020-06-01 22:33:16 +08:00
    @jason94 你这么写倒也挺好, 就是如果有在 constructor 之后才添加进去的事件, 就不会执行了, 如:
    setTimeout(() => { chain.eat() }, 5000)
    mxT52CRuqR6o5
        3
    mxT52CRuqR6o5  
       2020-06-01 23:04:09 +08:00
    ```ts
    class Chain{
    constructor(promise){
    if(promise){
    this._promise=promise;
    }else{
    this._promise=Promise.resolve();
    }
    }
    eat(){
    return this._next(()=>{console.log('eat')});
    }
    work(){
    return this._next(()=>{console.log('work')});
    }
    sleep(ms){
    return this._next(async ()=>{
    await new Promise(resolve=>setTimeout(resolve,ms))
    });
    }
    _next(someAction){
    const nextPromise=(async ()=>{
    await this._promise;
    await someAction();
    })()
    return new Chain(nextPromise);
    }
    }
    ```
    我的思路,没测试,可能有 bug
    treemonster
        4
    treemonster  
       2020-06-01 23:06:56 +08:00   ❤️ 2
    class Chain{
    task=Promise.resolve()
    eat() {
    this.task=this.task.then(_=>console.log('eat'))
    return this
    }
    work() {
    this.task=this.task.then(_=>console.log('work'))
    return this
    }
    sleep(t) {
    this.task=this.task.then(_=>new Promise(r=>{
    console.log('sleep', t)
    setTimeout(r, t)
    }))
    return this
    }
    }

    promise 写很简单
    xiaoming1992
        5
    xiaoming1992  
    OP
       2020-06-02 00:00:33 +08:00
    @mxT52CRuqR6o5 @treemonster 大概一瞄,应该是没什么问题的。我当时的思路就跟 4 楼的一样,可是写的丑多了。。。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2342 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 15:54 · PVG 23:54 · LAX 07:54 · JFK 10:54
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.