Pregunta ¿Por qué setTimeout () "se rompe" para valores de retardo de milisegundos grandes?


Encontré un comportamiento inesperado al pasar un valor de milisegundos grandes a setTimeout(). Por ejemplo,

setTimeout(some_callback, Number.MAX_VALUE);

y

setTimeout(some_callback, Infinity);

ambas causas some_callback para ser ejecutado casi de inmediato, como si hubiera pasado 0 en lugar de un gran número como el retraso.

¿Por qué pasó esto?


75
2017-08-12 14:13


origen


Respuestas:


Esto se debe a setTimeout utilizando un int 32 bits para almacenar el retraso por lo que el valor máximo permitido sería

2147483647

si intentas

2147483648

obtienes tu problema ocurriendo.

Solo puedo suponer que esto está causando alguna forma de excepción interna en el motor JS y que hace que la función se active inmediatamente en lugar de no funcionar.


107
2017-08-12 14:19



Alguna explicación aquí: http://closure-library.googlecode.com/svn/docs/closure_goog_timer_timer.js.source.html

Los valores de tiempo de espera demasiado grandes para caber en un entero de 32 bits con signo pueden causar   desbordamiento en FF, Safari y Chrome, lo que provoca el tiempo de espera   programado de inmediato. Tiene más sentido simplemente no programar estos   tiempos de espera, ya que 24.8 días está más allá de una expectativa razonable para el   navegador para permanecer abierto


18
2018-02-14 17:15



Puedes usar:

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

15
2017-08-12 08:37



Me tropecé con esto cuando traté de cerrar la sesión automáticamente a un usuario con una sesión vencida. Mi solución fue restablecer el tiempo de espera después de un día y mantener la funcionalidad para usar clearTimeout.

Aquí hay un pequeño prototipo de ejemplo:

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

Uso:

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

Y puedes limpiarlo con el stopTimer método:

timer.stopTimer();

0
2017-07-15 12:47



Consulte el documento del nodo en Timers aquí: https://nodejs.org/api/timers.html (asumiendo lo mismo en js también, ya que es un término tan ubicuo ahora en evento basado en bucle

En breve:

Cuando la demora es mayor que 2147483647 o menor que 1, la demora se establecerá en 1.

y la demora es:

La cantidad de milisegundos que debe esperar antes de llamar a la devolución de llamada.

Parece que su valor de tiempo de espera se está predeterminado a un valor inesperado a lo largo de estas reglas, posiblemente?


0
2017-07-30 02:45



Number.MAX_VALUE

en realidad no es un número entero. El valor máximo permitido para setTimeout es probablemente 2 ^ 31 o 2 ^ 32. Tratar

parseInt(Number.MAX_VALUE) 

y obtienes 1 de vuelta en lugar de 1.7976931348623157e + 308.


-2
2017-08-12 14:24