javascript - setTimeout 回调在 Firefox 和 Chrome 中的执行顺序不同

标签 javascript settimeout event-loop

当我在 Firefox 和 Chrome 中运行这段代码时,结果是不同的:

function run() {
  setTimeout(() => console.log("1"), 0);
  setTimeout(() => console.log("2"), 100);

  let start = Date.now();
  while (Date.now() - start < 200) {
    // do nothing
  }
  setTimeout(() => {
    console.log("3");
  }, 0);

  start = Date.now();
  while (Date.now() - start < 200) {
    // do nothing
  }
  setTimeout(() => {
    console.log("4");
  }, 0);
}

run();
在 Chrome(和 Node.js)中,打印如下:
1
3
2
4
在 Firefox 中,打印如下:
1
2
3
4
但是如果我删除第 2 行( setTimeout(() => console.log("1"), 0); ),那么每个平台上都会打印相同的内容:
2
3
4
如何解释这些不同的结果?
谢谢!

最佳答案

解释:没关系。
何时将延迟的“消息”添加到事件循环消息队列中的细节是实现细节,而不是记录在案的保证。当您的函数将控制权交还给事件循环时,您所有的 setTimeout call 有资格执行(其中三个计划立即运行,其中一个计划在 100 毫秒内运行),并且您已经保证自您安排它以来至少有 400 毫秒。
两者之间的区别可能很简单,就像他们是否选择在新项目插入之前或之后立即寻找已经准备好的延迟任务(从延迟队列移动到主“准备就绪”消息队列)主消息队列。 Chrome 选择在 3 之后立即移动已安排(因此 3 进入,然后是延迟的 2 ),Firefox 紧接在之前(在 2 放入之前移入 3)。
在不违反任何书面保证的情况下,它们都可以在下一个版本中进行更改。不要依赖它,不要期望它稳定。 While immediately scheduled tasks are guaranteed to execute in FIFO order , there are no guarantees on when deferred tasks get moved onto the "ready-to-go" message queue .规范似乎要求 1 , 34按该顺序执行(因为它们都立即准备就绪,而不是延迟),只有 2 的顺序灵活,但即使这样也不是真正的保证; the various ways in which an "immediate" setTimeout task may not actually be scheduled immediately 会变得很奇怪.
您可能对 why setTimeout can take longer than expected 上的 MDN 文档感兴趣;它通过副作用解释了事件循环的许多工作原理,即使它仔细地不保证您正在探索的细节。

关于javascript - setTimeout 回调在 Firefox 和 Chrome 中的执行顺序不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72737324/

相关文章:

javascript - 对所有用户使用 Office 365 身份验证

javascript - 延迟为1调用setTimeout的目的是什么?

javascript - 使用 setTimeout 绕过 IE 的长时间运行脚本警告

javascript - 如何区分两个 "onpause"事件 - 由单击 “pause” 按钮引起,以及由到达媒体片段末尾引起?

javascript - iOS safari 浏览器中录音的音频质量很差

javascript - 调用 .play() 会产生 "Uncaught (in promise) DOMException: The element has no supported sources."错误

javascript - 事件循环更喜欢微任务队列而不是回调队列?

javascript - 当alert()框打开并且在一段时间内没有点击 "OK"时如何重定向页面

events - 什么是浏览器事件循环?

javascript - 在 Async/Await 下留下无用的同步代码是一种反模式吗?