【问题标题】:Does the Microtask Queue have more priority than the Macrotask Queue?Microtask Queue 是否比 Macrotask Queue 具有更高的优先级?
【发布时间】:2021-12-09 00:14:26
【问题描述】:

如果Microtask Queue的优先级高于Macrotask Queue,为什么控制台日志的顺序是

  • scriptStart
  • scriptEnd
  • setTimeout
  • Response

而不是

  • scriptStart
  • scriptEnd
  • Response
  • setTimeout

鉴于for(let i=0;i<100000000;i++){ const start = Date.now(); } 需要足够的时间来保持主线程忙碌,直到 fetch 的响应到达?

完整代码

console.log("scriptStart")

setTimeout(() => {
  console.log("setTimeout");
}, 0);

fetch("https://jsonplaceholder.typicode.com/todos/1").then(() => {
  console.log('Response');
});

for (let i = 0; i < 100000000; i++) {
  const start = Date.now();
}
console.log("scriptEnd")

【问题讨论】:

  • 微任务队列没有任何优先级系统,队列中的微任务将在 JS 堆栈为空或在下一个微任务检查点时立即执行。但是这里 fetch.then 微任务只会在另一个任务中排队。
  • 相关(如果不是欺骗)stackoverflow.com/questions/62035390/…

标签: javascript v8 event-loop


【解决方案1】:

因为解释器是单线程的。看起来您将任务误认为是线程。他们不是。它们只是回调的链接列表。

解释器的工作方式如下:

    START
      │
      ▼
    execute
    javascript
      │
      ▼
    Event loop
    ┌──────────┐
    │          │
    │          │
    │          ▼
    │        check if there's any  ─────────▶ handle event
    │        event completion                       │
    │          │                                    │
    │          ▼                                    │
    │        check if we need to execute  ◀─────────┘
    │        any javascript in ───────────────▶ execute
    │        the microtask list                javascript
    │          │                                    │
    │          ▼                                    │
    │        check if we need to execute  ◀─────────┘
    │        any javascript in ───────────────▶ execute
    │        the macrotask list                javascript
    │          │                                    │
    │          │                                    │
    └────◀─────┴─────────────────◀──────────────────┘

都是循环。没有什么是并行运行的。因此,只要您正在执行 javascript,您就不会进入事件循环。

注意:如果您使用的是 worker_threads 或 webworkers,那就另当别论了,因为它们确实会产生线程。

【讨论】:

    【解决方案2】:

    正如您在调试器的网络选项卡中看到的,对服务器的请求仅在线程被释放时才开始(for 循环结束)。所以,当fetch 正在从服务器接收数据时,setTimeout 有时间去做。

    【讨论】:

    • 另外,虽然 Promise 在 Microtask 队列中,但问题也使用外部资源(即 API 请求)
    • 那么我不明白的是为什么浏览器要等待线程被释放(for循环结束)才能发出请求?
    猜你喜欢
    • 2016-02-24
    • 2020-05-26
    • 2014-08-22
    • 1970-01-01
    • 2020-10-10
    • 1970-01-01
    • 1970-01-01
    • 2018-12-02
    • 2015-05-09
    相关资源
    最近更新 更多