回答

具体分析

执行顺序图例

在一个 EventLoop 中,先执行宏任务,再执行微任务,全部执行后开始新的 EventLoop。
image.png
其中:

  1. 主线程:执行同步任务。
  2. 宏任务(macro-task)队列:setTimeout,setInterval
  3. 微任务(micro-task)队列:Promise

    一个小例子

    ```typescript // 以下代码的执行顺序

setTimeout(() => { console.log(1); // 1 }); new Promise(res => { console.log(2); // 2 res(); }).then(() => { Promise.resolve().then(() => { console.log(3); // 3 }); console.log(4); // 4 setTimeout(() => { console.log(5); // 5 }); }); console.log(6); // 6 ``` 正确答案是:2 6 4 3 1 5。
为什么?(为了简化描述,1 表示 1 所在的函数)

  1. 1 推入下一轮 EventLoop 的宏任务队列,因为在 setTimeout 中,且其时间参数为 0。
  2. 2 推入主线程,因为 Promise 具有创建即执行的机制。
  3. 345 推入微任务队列,因为在 Promise.then 中。
  4. 6 推入主线程
  5. 执行主线程,输出:2 6
  6. 执行当前宏任务队列,没有。
  7. 执行当前微任务队列,执行345函数。
    1. 3 会推入微队列。
    2. 4 会推入主线程执行,输出:4
    3. 5 会推入下一轮 EventLoop 的宏任务队列,但下一轮有宏任务,所以会推入下下一轮。
    4. 微任务中还有新加的 3,推入主线程执行,输出:3
  8. 本轮 EventLoop 结束,进入下一轮 EventLoop,输出:1
  9. 推入下下一轮 EventLoop,输出:5

    参考资料

  10. 10分钟理解JS引擎的执行机制_前端进阶 - SegmentFault 思否 [https://segmentfault.com/a/1190000012806637]