为什么setTimeout()"中断"大毫秒延迟值?

Mat*_*all 95 javascript settimeout

当传递一个大的毫秒值时,我遇到了一些意想不到的行为setTimeout().例如,

setTimeout(some_callback, Number.MAX_VALUE);
Run Code Online (Sandbox Code Playgroud)

setTimeout(some_callback, Infinity);
Run Code Online (Sandbox Code Playgroud)

两者都导致some_callback几乎立即运行,好像我已经通过0而不是大量的延迟.

为什么会这样?

One*_*HOT 131

这是由于setTimeout使用32位int来存储延迟,因此允许的最大值将是

2147483647
Run Code Online (Sandbox Code Playgroud)

如果你试试

2147483648
Run Code Online (Sandbox Code Playgroud)

你发现了问题.

我只能假设这会在JS引擎中引起某种形式的内部异常并导致函数立即触发而不是根本不触发.

  • @maxp那是因为`49999861776383%2147483648 === 2147483647` (6认同)
  • @NickCoad 两个数字都会延迟相同的数量(即,从有符号的 32 位角度来看,49999861776383 与 2147483647 相同)。将它们以二进制形式写出,并取最后 31 位,它们都是 1。 (4认同)

war*_*ech 21

这里有一些解释:http://closure-library.googlecode.com/svn/docs/closure_goog_timer_timer.js.source.html

超时值太大而不适合签名的32位整数可能会导致FF,Safari和Chrome出现溢出,从而导致超时被立即调度.更简单的是不安排这些超时,因为24.8天超出浏览器保持开放的合理期望.

  • warpech 的回答很有道理——像 Node.JS 服务器这样的长时间运行的进程可能听起来像一个例外,但老实说,如果你有一些你想要确保在 24 天和几天内以毫秒精度发生的事情那么在面对服务器和机器错误时,您应该使用比 setTimeout 更强大的东西... (2认同)
  • 我在服务器上运行NodeJS中的Javascript,24.8天仍然很好,但我正在寻找一种更合理的方式来设置回调发生在1个月(30天)内.怎么办呢? (2认同)
  • 谁说?我的浏览器打开时间超过 24 天...;) (2认同)

Ron*_*nen 20

您可以使用:

function runAtDate(date, func) {
    var now = (new Date()).getTime();
    var then = date.getTime();
    var diff = Math.max((then - now), 0);
    if (diff > 0x7FFFFFFF) //setTimeout limit is MAX_INT32=(2^31-1)
        setTimeout(function() {runAtDate(date, func);}, 0x7FFFFFFF);
    else
        setTimeout(func, diff);
}
Run Code Online (Sandbox Code Playgroud)

  • 只要您在该函数中进行簿记并替换要取消的 timeoutId,您就不会真正失去取消它的能力。 (3认同)
  • 这很酷,但是由于递归,我们失去了使用ClearTimeout的能力。 (2认同)

小智 6

在此处查看计时器上的节点文档:https : //nodejs.org/api/timers.html(假设在 js 中也是如此,因为它现在在基于事件循环中是一个无处不在的术语

简而言之:

当延迟大于 2147483647 或小于 1 时,延迟将设置为 1。

延迟是:

在调用回调之前等待的毫秒数。

似乎您的超时值被默认为这些规则中的意外值,可能吗?