admin管理员组

文章数量:1134589

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?

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?

Share Improve this question asked Aug 12, 2010 at 14:13 Matt BallMatt Ball 360k102 gold badges652 silver badges719 bronze badges 1
  • 1 Because it's limited to 32-bit, which is 2 power 32. If you calculate it you get 4294967296. Now, you need the first bit to decide whether it is a negative or positive number. So you get 2 power 31 and you get half of 4294967296, which is 2147483648. But zero is a positive number so 2147483647. – Joe Commented Jan 21, 2021 at 11:10
Add a comment  | 

7 Answers 7

Reset to default 183

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.

You can use:

const MAX_INT32 = 2 ** 31 - 1; // 2147483647 (hex 0x7FFFFFFF)

function runAtDate(date, func) {
    const now = Date.now();
    const then = date.valueOf();
    const diff = Math.max(then - now, 0);
    if (diff > MAX_INT32) {
        setTimeout(() => {
            runAtDate(date, func, MAX_INT32);
        }, MAX_INT32);
    } else {
        setTimeout(func, diff);
    }
}

Or, a slightly more involved version that allows you to clear the timeout using the returned value:

const MAX_INT32 = 2 ** 31 - 1;

function runAtDate(date, func, msPerTimeout = MAX_INT32) {
    const timeout = arguments[3] ?? { valueOf() { return this._val; } };
    const now = Date.now();
    const then = date.valueOf();
    const diff = Math.max(then - now, 0);
    if (diff > msPerTimeout) {
        timeout._val = setTimeout(() => {
            runAtDate(date, func, msPerTimeout, timeout);
        }, msPerTimeout);
    } else {
        timeout._val = setTimeout(func, diff);
    }

    return timeout
}

// Usage (using a much lower `msPerTimeout` value for demo purposes)

void (async () => {
    const delay = (ms) => new Promise((res) => setTimeout(res, ms));

    // v1 (running to completion)
    {
        const timeout = runAtDate(
            Date.now() + 1000,
            () => console.log('v1 done! 

本文标签: javascriptWhy does setTimeout() quotbreakquot for large millisecond delay valuesStack Overflow