代码之家  ›  专栏  ›  技术社区  ›  Matt Ball

为什么settimeout()对于大毫秒延迟值是“break”?

  •  84
  • Matt Ball  · 技术社区  · 15 年前

    我在向 setTimeout() . 例如,

    setTimeout(some_callback, Number.MAX_VALUE);
    

    setTimeout(some_callback, Infinity);
    

    两个原因 some_callback 马上就跑,好像我已经通过了 0 而不是一个大数作为延迟。

    为什么会这样?

    6 回复  |  直到 7 年前
        1
  •  120
  •   Matt Ball    14 年前

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

    2147483647
    

    如果你尝试

    2147483648
    

    你的问题就发生了。

    我只能假定这会导致JS引擎中出现某种形式的内部异常,并导致函数立即启动,而不是完全不启动。

        2
  •  21
  •   warpech    14 年前

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

    超时值太大,无法放入带符号的32位整数中,可能会导致 FF、Safari和Chrome溢出,导致超时 立即安排。更合理的做法是不安排这些 超时,因为24.8天超出了 浏览器保持打开状态。

        3
  •  16
  •   Ronen    12 年前

    你可以使用:

    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);
    }
    
        4
  •  1
  •   Tim    7 年前

    当我试图自动注销会话过期的用户时,我偶然发现了这个问题。我的解决方案是在一天后重置超时,并保留使用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();
    
        5
  •  1
  •   SillyGilly    7 年前

    在这里查看节点文档计时器: https://nodejs.org/api/timers.html (在JS中也假设相同,因为它现在是基于事件循环的普遍术语

    简而言之:

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

    延迟是:

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

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

        6
  •  -2
  •   Osmund    15 年前
    Number.MAX_VALUE
    

    实际上不是整数。设置超时的最大允许值可能是2^31或2^32。尝试

    parseInt(Number.MAX_VALUE) 
    

    你得到1而不是1.7976931348623157E+308。