Je suis tombé sur un comportement inattendu lors du passage d'une grande valeur en millisecondes à setTimeout()
. Par exemple,
setTimeout(some_callback, Number.MAX_VALUE);
et
setTimeout(some_callback, Infinity);
les deux causent some_callback
à exécuter presque immédiatement, comme si j'avais réussi 0
au lieu d'un grand nombre comme délai.
Pourquoi cela arrive-t-il?
Cela est dû au fait que setTimeout utilise un int 32 bits pour stocker le retard, de sorte que la valeur maximale autorisée serait
2147483647
si tu essayes
2147483648
vous obtenez votre problème.
Je peux seulement présumer que cela provoque une forme d'exception interne dans le moteur JS et provoque le déclenchement immédiat de la fonction plutôt que pas du tout.
Quelques explications ici: http://closure-library.googlecode.com/svn/docs/closure_goog_timer_timer.js.source.html
Les valeurs de délai d'attente trop grandes pour tenir dans un entier 32 bits signé peuvent provoquer un débordement dans FF, Safari et Chrome, entraînant la planification immédiate du délai d'attente. Il est plus logique de ne pas planifier ces délais, car 24,8 jours dépassent une attente raisonnable pour que le navigateur reste ouvert.
Vous pouvez utiliser:
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);
}
Je suis tombé dessus lorsque j'ai essayé de déconnecter automatiquement un utilisateur avec une session expirée. Ma solution était de simplement réinitialiser le délai d'attente après une journée et de conserver la fonctionnalité pour utiliser clearTimeout.
Voici un petit exemple de prototype:
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);
}
};
Usage:
var timer = new Timer('2018-08-17 14:05:00', function() {
document.location.reload();
});
Et vous pouvez l'effacer avec la méthode stopTimer
:
timer.stopTimer();
Consultez la documentation du nœud sur les temporisateurs ici: https://nodejs.org/api/timers.html (en supposant la même chose sur js également car c'est un terme omniprésent maintenant dans la boucle d'événements basée sur
En bref:
Lorsque le retard est supérieur à 2147483647 ou inférieur à 1, le retard sera réglé sur 1.
et le retard est:
Le nombre de millisecondes à attendre avant d'appeler le rappel.
On dirait que votre valeur de délai d'attente est par défaut une valeur inattendue le long de ces règles, peut-être?
Je ne peux pas commenter mais répondre à toutes les personnes. Cela prend une valeur non signée (vous ne pouvez évidemment pas attendre des millisecondes négatives) Donc, comme la valeur maximale est "2147483647" lorsque vous entrez une valeur plus élevée, elle commence à passer de 0.
Retard essentiellement = {VALUE}% 2147483647.
Donc, en utilisant un retard de 2147483648, cela ferait 1 milliseconde, donc, proc instantané.