Почему setTimeout () "прерывается" для больших значений задержки в миллисекундах? - PullRequest
90 голосов
/ 12 августа 2010

Я столкнулся с неожиданным поведением при передаче большого значения в миллисекундах в setTimeout(). Например,

setTimeout(some_callback, Number.MAX_VALUE);

и

setTimeout(some_callback, Infinity);

оба приводят к тому, что some_callback запускается почти сразу, как если бы я передал 0 вместо большого числа в качестве задержки.

Почему это происходит?

Ответы [ 7 ]

127 голосов
/ 12 августа 2010

Это связано с тем, что setTimeout использует 32-битное int для хранения задержки, поэтому максимально допустимое значение будет

2147483647

если вы попробуете

2147483648

у вас возникла проблема.

Я могу только предположить, что это вызывает некое внутреннее исключение в JS Engine и вызывает немедленное срабатывание функции, а не ее вообще.

21 голосов
/ 14 февраля 2011

Некоторое объяснение здесь: http://closure -library.googlecode.com / svn / docs / closure_goog_timer_timer.js.source.html

значения времени ожидания слишком велики32-разрядное целое число со знаком может вызвать переполнение в FF, Safari и Chrome, что приводит к немедленному планированию времени ожидания.Более разумно просто не планировать эти тайм-ауты, поскольку 24,8 дня больше, чем разумное ожидание, чтобы браузер оставался открытым.

17 голосов
/ 12 августа 2013

Вы можете использовать:

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);
}
1 голос
/ 30 июля 2018

Просмотрите документацию по узлам по таймерам здесь: https://nodejs.org/api/timers.html (при условии, что то же самое относится и к js, так как это такой повсеместный термин, который используется сейчас в основе цикла событий

Короче:

Если задержка больше 2147483647 или меньше 1, задержка будет установлена ​​на 1.

, а задержка:

Количество миллисекунд доподождите, прежде чем вызвать обратный вызов.

Похоже, ваше значение тайм-аута по умолчанию соответствует неожиданному значению в этих правилах, возможно?

1 голос
/ 15 июля 2018

Я наткнулся на это, когда попытался автоматически выйти из системы с просроченным сеансом. Мое решение состояло в том, чтобы просто сбросить тайм-аут после одного дня и сохранить функциональность для использования 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();
0 голосов
/ 22 июня 2019

Не могу комментировать, но ответить всем людям.Он принимает значение без знака (очевидно, вы не можете ждать отрицательных миллисекунд). Так как максимальное значение равно «2147483647», при вводе более высокого значения оно начинается с 0.

В основном задержка = {VALUE}%2147483647.

Таким образом, использование задержки 2147483648 сделает ее равной 1 миллисекунде, следовательно, мгновенный процесс.

0 голосов
/ 12 августа 2010
Number.MAX_VALUE

на самом деле не является целым числом.Максимально допустимое значение для setTimeout, скорее всего, 2 ^ 31 или 2 ^ 32.Попробуйте

parseInt(Number.MAX_VALUE) 

, и вы получите 1 обратно вместо 1.7976931348623157e + 308.

...