Почему setTimeout() "ломается" для больших значений миллисекундной задержки?

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

setTimeout(some_callback, Number.MAX_VALUE);

и

setTimeout(some_callback, Infinity);

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

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

Ответ 1

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

2147483647

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

2147483648

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

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

Ответ 2

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

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

Ответ 3

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

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

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

timer.stopTimer();

Ответ 5

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

Короче:

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

и задержка составляет:

Количество миллисекунд ожидания до обратного вызова.

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

Ответ 6

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

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

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

Ответ 7

Number.MAX_VALUE

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

parseInt(Number.MAX_VALUE) 

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