为什么这个 Node.js 脚本每次都会产生不同的输出?

问题描述 投票:0回答:1

该脚本来自Nodejs入门书籍。这部分是关于Javascript的事件循环。

const sleep_st = (t) => new Promise((r) => setTimeout(r, t));
const sleep_im = () => new Promise((r) => setImmediate(r));

(async () => {
    setImmediate(() => console.log(1));
    console.log(2);
    await sleep_st(0);
    setImmediate(() => console.log(3));
    console.log(4);
})();

两个可能的输出是“2 4 1 3”和“2 1 4 3”。

我希望输出始终一致。

javascript node.js event-loop
1个回答
0
投票

由于 JavaScript 事件循环、微任务和宏任务之间的相互作用,代码每次都会生成不同顺序的数字,从而引入了不确定性行为。

执行顺序

  • 事件循环在移至下一个宏任务之前处理所有微任务。
  • setImmediate 任务的处理顺序取决于环境以及相对于当前事件循环标记的添加时间。

逐步执行:

  1. 开始执行:

    • setImmediate(() => console.log(1)):安排宏任务记录 1。
    • console.log(2):同步记录2。
    • await sleep_st(0):调度一个宏任务(setTimeout 延迟为 0)并暂停函数直到它解决。
  2. 宏任务:sleep_st(0) 解决:

    • 宏任务完成后,它恢复异步功能。
  3. 异步函数内部:

    • setImmediate(() => console.log(3)):安排另一个宏任务。
    • console.log(4):同步记录4。
  4. 事件循环执行:

    • 事件循环按以下顺序处理任务:
      1. 剩余的宏任务(例如,setImmediate 回调)。
      2. 前一阶段安排的微任务。

订单变更原因:

  1. 设置立即计时:
    • setImmediate 相对于 setTimeout 的时间取决于环境(Node.js 处理它们的方式与浏览器不同)。
    • 在某些情况下,setImmediate 任务可以在 setTimeout 之前或之后以 0 毫秒延迟运行,具体取决于它们的计划时间。
  2. 比赛条件:
    • setImmediate 和 setTimeout(即使是 0ms)可以竞相执行它们的回调。
    • setImmediate(() => console.log(1)) 和 setImmediate(() => console.log(3)) 的确切时间引入了可变性。
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.