【问题标题】:Understanding SetTimeout order了解 SetTimeout 顺序
【发布时间】:2015-10-13 16:58:07
【问题描述】:

我正在仔细阅读一组在线 javascript 面试问题,并注意到以下问题:

function printing() {
  console.log(1); 
  setTimeout(function() { console.log(2); }, 1); 
  setTimeout(function() { console.log(3); }, 2); 
  setTimeout(function() { console.log(4); }, 0); 
  console.log(5);
}
printing();

我希望以下代码将以下内容打印到控制台:1,5,4,3,2 我的原因是 console.log(1) 和 console.log(2) 先执行,而 setTimeout 被发送到 eventloop 等待一切先完成。打印 5 后,JS 将查看队列,然后 4、3、2 将推送/弹出。

但是,在我的 Chrome 浏览器上,我注意到 1,5,2,4,3 出现了。

我很困惑,但同时有一种预感,这可能是由于超时延迟的小幅增量导致了打嗝(可能是浏览器问题?)。我这样做的原因是因为我在每个数字后面添加了两个零,这样延迟变为 100、200 和 0。

谁能澄清幕后发生的事情,以及我应该知道的有关延迟的任何陷阱?

【问题讨论】:

  • 非常确定超时的最小有效值为 1,因此 0 被移到 1,因此发生在之后。没有把握。无论如何,我不使用小于 16 毫秒 (60Hz) 的计时器,因为这是 Windows 上的默认计时器分辨率,我不想仅仅为了它而使用高分辨率计时器。
  • 我注意到以下链接,其中最小值为 4 毫秒和 10 毫秒,具体取决于浏览器:stackoverflow.com/questions/9647215/…
  • 可能值得注意的是,在w3 spec 的第 6.4 节中,它声明了... timeout is less than 4, then increase timeout to 4(如果根据规范,您的 ms 值是 0-3,它将被设置为 4),然后,您可能会发现以下关于 Javascript 计时有用 How Javascript Timers work

标签: javascript


【解决方案1】:

这里我给你一个执行过程的例子:

  console.log(1);                                   // Run log "1"
  setTimeout(function() { console.log(2); }, 1);    // Add to queue timer1
  setTimeout(function() { console.log(3); }, 2);    // Add to queue timer2 
  setTimeout(function() { console.log(4); }, 0);    // Add to queue timer3
  console.log(5);                                   // Run log "5"
  // In queue [timer1, timer2, timer3]

  // [tick timer 1 => 0 time left => execute] log "2"
  // [tick timer 2 => 1 time left]
  // [timer 3 => 0 time left => execute] log "4"
  // [tick timer 2 => 0 time left => execute] log "3"

功能上setTimeout(... , 0)setTimeout(..., 1) 的工作方式相同。当我们勾选 “超时队列” 中的每个计时器时,我们还会检查是否还有剩余时间。所以setTimeout(..., 1) 会打勾并执行,而setTimeout(... , 0) 只会执行。

【讨论】:

  • 啊,这很有意义。由于 JS 是同步的,它会通过定时器队列的顺序,并首先使 timer1 过期,从而使其执行。真的很有帮助,谢谢!
  • 每个浏览器/引擎都一样吗?我的火狐日志1 5 4 2 3
  • @Anonymous0day 不,不是。不同的浏览器可以不同地处理计时器。我上面解释的是它是如何在 OP 浏览器中发生的(我假设它是 chrome)。看起来 Firefox 会以不同的方式标记队列中的每个计时器(它可能会首先标记时间最短的那个,但这是一个猜测)。
  • @Spencer Wieczorek 太好了,我不知道,现在我知道了!谢谢你的解释!
【解决方案2】:

您必须了解调用堆栈。所有函数调用都放在调用堆栈上,如果堆栈为空,则调用该函数。如果堆栈有条目,则在堆栈上的当前调用完成之前不会调用该函数。

超时会在调用超时时将调用置于调用堆栈中。他们异步执行此操作。因此,可以在当前执行期间将调用放在调用堆栈上。

超时没有优先级,首先在堆栈上执行。 1 毫秒超时比 0 毫秒到达调用堆栈,因此首先执行。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多