Why does setTimeout() "break" for large millisecond delay values?

Viewed 48875

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?

7 Answers

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?

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.

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();
Related