Frage Warum "bricht" setTimeout () für Verzögerungswerte mit großen Millisekunden?


Ich bin auf ein unerwartetes Verhalten gestoßen, als ich einen großen Millisekunden-Wert übergeben habe setTimeout(). Zum Beispiel,

setTimeout(some_callback, Number.MAX_VALUE);

und

setTimeout(some_callback, Infinity);

beide verursachen some_callback fast sofort ausgeführt werden, als ob ich bestanden hätte 0 anstelle einer großen Zahl als die Verzögerung.

Warum passiert das?


75
2017-08-12 14:13


Ursprung


Antworten:


Dies liegt an setTimeout, das einen 32-Bit-Int verwendet, um die Verzögerung zu speichern, so dass der maximal zulässige Wert wäre

2147483647

wenn du es versuchst

2147483648

Du bekommst dein Problem.

Ich kann nur vermuten, dass dies eine Form von interner Ausnahme in der JS-Engine verursacht und bewirkt, dass die Funktion sofort und nicht sofort ausgelöst wird.


107
2017-08-12 14:19



Einige Erklärung hier: http://closure-library.googlecode.com/svn/docs/closure_goog_timer_timer.js.source.html

Timeout-Werte, die zu groß sind, um in eine vorzeichenbehaftete 32-Bit-Ganzzahl zu passen, können dazu führen   Überlauf in FF, Safari und Chrome, was zu einem Timeout führt   sofort geplant. Es macht mehr Sinn, diese einfach nicht zu planen   Timeouts, da 24,8 Tage eine vernünftige Erwartung für die   Browser, um offen zu bleiben.


18
2018-02-14 17:15



Sie können verwenden:

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



Ich stolperte darüber, als ich versuchte, einen Benutzer mit einer abgelaufenen Sitzung automatisch abzumelden. Meine Lösung bestand darin, das Zeitlimit nach einem Tag zurückzusetzen und die Funktionalität auf clearTimeout zu beschränken.

Hier ist ein kleines Prototyp-Beispiel:

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

Verwendung:

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

Und Sie können es mit dem löschen stopTimer Methode:

timer.stopTimer();

0
2017-07-15 12:47



Schauen Sie sich das Node-Dokument zu den Timern hier an: https://nodejs.org/api/timers.html (Gleiches gilt auch für js, da es sich um einen so ubiquitären Begriff handelt, der jetzt auf einer Ereignisschleife basiert

Zusamenfassend:

Wenn die Verzögerung größer als 2147483647 oder kleiner als 1 ist, wird die Verzögerung auf 1 gesetzt.

und die Verzögerung ist:

Die Anzahl der Millisekunden, die gewartet werden muss, bevor der Rückruf aufgerufen wird.

Scheint so, als ob Ihr Timeout-Wert nach diesen Regeln auf einen unerwarteten Wert gesetzt wird, möglicherweise?


0
2017-07-30 02:45



Number.MAX_VALUE

ist eigentlich keine ganze Zahl. Der maximal zulässige Wert für setTimeout ist wahrscheinlich 2 ^ 31 oder 2 ^ 32. Versuchen

parseInt(Number.MAX_VALUE) 

und du bekommst 1 zurück statt 1.7976931348623157e + 308.


-2
2017-08-12 14:24