Why does setTimeout() "break" for large millisecond delay values?
JavascriptSettimeoutJavascript Problem Overview
I came across some unexpected behavior when passing a large millisecond value to setTimeout()
. For instance,
setTimeout(some_callback, Number.MAX_VALUE);
and
setTimeout(some_callback, Infinity);
both cause some_callback
to be run almost immediately, as if I'd passed 0
instead of a large number as the delay.
Why does this happen?
Javascript Solutions
Solution 1 - Javascript
This is due to setTimeout using a 32 bit int to store the delay so the max value allowed would be
2147483647
if you try
2147483648
you get your problem occurring.
I can only presume this is causing some form of internal exception in the JS Engine and causing the function to fire immediately rather than not at all.
Solution 2 - Javascript
You can use:
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);
}
Solution 3 - Javascript
Some explanation here: http://closure-library.googlecode.com/svn/docs/closure_goog_timer_timer.js.source.html
> Timeout values too big to fit into a signed 32-bit integer may cause > overflow in FF, Safari, and Chrome, resulting in the timeout being > scheduled immediately. It makes more sense simply not to schedule these > timeouts, since 24.8 days is beyond a reasonable expectation for the > browser to stay open.
Solution 4 - Javascript
Check out the node doc on Timers here: https://nodejs.org/api/timers.html (assuming same across js as well since it's such an ubiquitous term now in event loop based
In short:
When delay is larger than 2147483647 or less than 1, the delay will be set to 1.
and delay is:
The number of milliseconds to wait before calling the callback.
Seems like your timeout value is being defaulted to an unexpected value along these rules, possibly?
Solution 5 - Javascript
Can't comment but to answer all the people. It takes unsigned value ( you can't wait negative milliseconds obviously ) So since max value is "2147483647" when you enter a higher value it start going from 0.
Basically delay = {VALUE} % 2147483647.
So using delay of 2147483648 would make it 1 millisecond, therefore, instant proc.
Solution 6 - Javascript
I stumbled on this when I tried to automatically logout a user with an expired session. My solution was to just reset the timeout after one day, and keep the functionality to use clearTimeout.
Here is a little prototype example:
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();
});
And you may clear it with the stopTimer
method:
timer.stopTimer();
Solution 7 - Javascript
Number.MAX_VALUE
is actually not an integer. The maximum allowable value for setTimeout is likely 2^31 or 2^32. Try
parseInt(Number.MAX_VALUE)
and you get 1 back instead of 1.7976931348623157e+308.