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

时间:2010-08-12 14:13:58

标签: javascript settimeout

将大毫秒值传递给setTimeout()时,我遇到了一些意外行为。例如,

setTimeout(some_callback, Number.MAX_VALUE);

setTimeout(some_callback, Infinity);

两者都会导致some_callback几乎立即运行,好像我已经通过0而不是大数字作为延迟。

为什么会这样?

7 个答案:

答案 0 :(得分:126)

这是由于setTimeout使用32位int来存储延迟所以允许的最大值是

2147483647

如果你尝试

2147483648

你发现了问题。

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

答案 1 :(得分:21)

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

  

超时值太大而不适合签名的32位整数可能会导致   在FF,Safari和Chrome中溢出,导致超时   立即安排。仅仅不安排这些更有意义   超时,因为24.8天超出了合理的预期   浏览器保持开放。

答案 2 :(得分:16)

您可以使用:

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);
}

答案 3 :(得分:1)

当我尝试自动注销会话已过期的用户时,我偶然发现了这一点。我的解决方案是在一天后重设超时,并保留使用clearTimeout的功能。

这是一个小小的原型示例:

Timer = function(execTime, callback) {
    if(!(execTime instanceof Date)) {
        execTime = new Date(execTime);
    }

    this.execTime = execTime;
    this.callback = callback;

    this.init();
};

Timer.prototype = {

    callback: null,
    execTime: null,

    _timeout : null,

    /**
     * Initialize and start timer
     */
    init : function() {
        this.checkTimer();
    },

    /**
     * Get the time of the callback execution should happen
     */
    getExecTime : function() {
        return this.execTime;
    },

    /**
     * Checks the current time with the execute time and executes callback accordingly
     */
    checkTimer : function() {
        clearTimeout(this._timeout);

        var now = new Date();
        var ms = this.getExecTime().getTime() - now.getTime();

        /**
         * Check if timer has expired
         */
        if(ms <= 0) {
            this.callback(this);

            return false;
        }

        /**
         * Check if ms is more than one day, then revered to one day
         */
        var max = (86400 * 1000);
        if(ms > max) {
            ms = max;
        }

        /**
         * Otherwise set timeout
         */
        this._timeout = setTimeout(function(self) {
            self.checkTimer();
        }, ms, this);
    },

    /**
     * Stops the timeout
     */
    stopTimer : function() {
        clearTimeout(this._timeout);
    }
};

用法:

var timer = new Timer('2018-08-17 14:05:00', function() {
    document.location.reload();
});

您可以使用stopTimer方法清除它:

timer.stopTimer();

答案 4 :(得分:1)

在此处查看有关Timers的节点文档:https://nodejs.org/api/timers.html(假设在js中也是如此,因为在基于事件循环的环境中,这是一个无处不在的术语

简而言之:

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

,延迟为:

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

似乎您可能按照这些规则将超时值默认设置为意外值?

答案 5 :(得分:0)

只好回答所有人。 它需要无符号值(您显然不能等待负毫秒) 因此,由于最大值是“ 2147483647”,当您输入较高的值时,它将从0开始。

基本延迟= {VALUE}%2147483647。

因此,使用2147483648的延迟将使其变为1毫秒,因此是即时触发。

答案 6 :(得分:-2)

Number.MAX_VALUE

实际上不是整数。 setTimeout的最大允许值可能是2 ^ 31或2 ^ 32。试试

parseInt(Number.MAX_VALUE) 

你得到1回而不是1.7976931348623157e + 308。