题目要求:

```javascript

// 执行 tom().eat(‘apple’).sleep(3000).play(‘game’)

输出 eat apple

// 过3s 再输出 play game

  1. <a name="Exruz"></a>
  2. ## 分析:
  3. 有先后顺序,先调的函数先执行,即先进先出,故这是一个明显的队列问题,因此首先需要一个队列,其次将调用的函数依次放入队列中,队列出队并执行,因为存在异步问题,即延迟 3s 问题,故必须等到出队的元素执行完毕方可以执行下一次出队
  4. <a name="AzZZo"></a>
  5. ## 解法 1
  6. 1.新建一个队列<br />2.把调用的函数放入队列中,每个函数执行完之后触发下一个 next <br />3.利用宏任务 setTimeout 在所有同步代码执行代码执行完再执行的原理将触发出队的操作放在这里<br />4.依次执行出队操作
  7. <a name="LuMGi"></a>
  8. ## ```javascript
  9. function tom() {
  10. const q = [];
  11. const next = function () {
  12. const fn = q.shift();
  13. fn && fn();
  14. };
  15. setTimeout(() => {
  16. next();
  17. });
  18. return {
  19. eat: function (params) {
  20. const eat_fn = () => {
  21. console.log(`eat ${params}`);
  22. next();
  23. };
  24. q.push(eat_fn);
  25. return this;
  26. },
  27. sleep: function (delay) {
  28. let sleep_fn = () => {
  29. setTimeout(() => {
  30. next();
  31. }, delay);
  32. };
  33. q.push(sleep_fn);
  34. return this;
  35. },
  36. play: function (params) {
  37. const play_fn = () => {
  38. console.log(`play ${params}`);
  39. next();
  40. };
  41. q.push(play_fn);
  42. return this;
  43. },
  44. };
  45. }
  46. tom().eat('apple').sleep(3000).play('game');

解法 2

1.新建一个队列
2.把调用的函数放入队列中,其中延迟函数封装成一个 Promise
3.利用微任务在所有同步代码执行代码执行完再执行的原理将触发出队的操作放在这里
4.依次执行出队操作,每一次出队必须等待上一个 Promise 执行完毕

```javascript

function tom() { const q = [];

// setTimeout(async () => { // while(q.length > 0) { // const fn = q.shift();

// if (typeof fn === ‘function’) { // await fn() // } // } // })

Promise.resolve().then(async () => { while (q.length > 0) { const fn = q.shift();

  if (typeof fn === 'function') {
    await fn();
  }
}

});

return { eat: function (params) { const eat_fn = () => { return console.log(eat ${params}); };

  q.push(eat_fn);

  return this;
},

sleep: function (delay) {
  let sleep_fn = async () => {
    return new Promise((resolve) => {
      setTimeout(() => {
        resolve();
      }, delay);
    });
  };

  q.push(sleep_fn);

  return this;
},

play: function (params) {
  const play_fn = () => {
    return console.log(`play ${params}`);
  };

  q.push(play_fn);

  return this;
},

}; }

tom() .eat(‘apple’) .sleep(3000) .play(‘game’) .sleep(3000) .eat(‘apple’) .sleep(3000) .play(‘game’);


解法 3


与 1、2 的区别在于利用拦截器统一做入队操作,写法上更简洁
<a name="8JyMg"></a>
## ```javascript
function tom() {
  const q = [];

  Promise.resolve().then(async () => {
    while(q.length) {
      const fn = q.shift();

      await fn();
    }
  });

  const events = {
    eat(params) {
      console.log(`eat ${params}`);
    },

    sleep(delay) {
      return new Promise((resolve) => {
        setTimeout(() => {
          resolve();
        }, delay);
      });
    },

    play(params) {
      console.log(`play ${params}`);
    },
  }

  return new Proxy(events, {
    get(target, p, receiver) {
      const fn = target[p];

      return function() {
        q.push(() => fn(...arguments));

        return receiver;
      };
    },
  });
}

tom()
  .eat('apple')
  .sleep(3000)
  .play('game')
  .sleep(3000)
  .eat('apple')
  .sleep(3000)
  .play('game')
  .sleep(3000)
  .play('game')
  .sleep(3000)
  .eat('apple')
  .sleep(3000)
  .play('game');