Skip to content

Instantly share code, notes, and snippets.

@ali-master
Created April 4, 2025 17:38
Show Gist options
  • Save ali-master/8c0aae7f27dc450eacb120c0a782bf16 to your computer and use it in GitHub Desktop.
Save ali-master/8c0aae7f27dc450eacb120c0a782bf16 to your computer and use it in GitHub Desktop.
setTimeout caps out at ~25 days. If you need a bigger timeout, use setBigTimeout.

Javascript Big Timeout

setTimeout caps out at ~25 days. If you need a bigger timeout, use setBigTimeout.

import { setBigTimeout } from "./mod.mts";

const FORTY_DAYS_IN_MILLISECONDS = 3.456e9;

// setTimeout doesn't handle big timeouts.
setTimeout(() => {
  console.log("Logs immediately! Bad!");
}, FORTY_DAYS_IN_MILLISECONDS);

// setBigTimeout works fine!
setBigTimeout(() => {
  console.log("It's been 40 days...no problem!");
}, FORTY_DAYS_IN_MILLISECONDS);

API reference

setBigTimeout(fn: () => unknown, delay: number | bigint): BigTimeout

Very similar to setTimeout, but allows a delay of arbitrary duration. Durations can be numbers or bigints.

Example:

import { setBigTimeout } from "./mod.mts";

const EIGHTY_FOUR_YEARS_IN_MILLISECONDS = 2.65e12;
setBigTimeout(() => {
  console.log("It's been 84 years...");
}, EIGHTY_FOUR_YEARS_IN_MILLISECONDS);

const ONE_MILLION_YEARS = 31536000000000000n;
setBigTimeout(() => {
  console.log("JAVASCRIPT WILL NEVER DIE");
}, ONE_MILLION_YEARS);

clearBigTimeout(bigTimeout: BigTimeout | Parameters<typeof clearTimeout>[0]): void

Very similar to clearTimeout, but clears big timeouts. Can also clear "normal" timeouts created by setTimeout and setInterval.

Example:

import { clearBigTimeout, setBigTimeout } from "./mod.mts";

const timeout = setBigTimeout(() => {
  console.log("This will never be executed");
}, 123456789);

clearBigTimeout(timeout);
// This value is somewhat arbitrary. It must be:
//
// - Less than `Number.MAX_SAFE_INTEGER`
// - Less than the maximum `setTimeout` value
//
// It's useful for this value to be large, as it minimizes time hogging the
// main thread, but that isn't a huge deal.
const MAX_REAL_DELAY = 2 ** 30;
const clear = Symbol("clear");
class BigTimeout {
#realTimeout: null | ReturnType<typeof setTimeout> = null;
constructor(fn: () => unknown, delay: number | bigint) {
if (delay < 0) {
throw new Error("setBigTimeout cannot be called with a negative delay");
}
let remainingDelay = delay;
const subtractNextDelay = () => {
if (typeof remainingDelay === "number") {
remainingDelay -= MAX_REAL_DELAY;
} else {
remainingDelay -= BigInt(MAX_REAL_DELAY);
}
};
const step = () => {
if (remainingDelay > MAX_REAL_DELAY) {
subtractNextDelay();
this.#realTimeout = setTimeout(step, MAX_REAL_DELAY);
} else {
this.#realTimeout = setTimeout(fn, Number(remainingDelay));
}
};
step();
}
[clear](): void {
if (this.#realTimeout) {
clearTimeout(this.#realTimeout);
this.#realTimeout = null;
}
}
}
/**
* `setTimeout` has a [maximum delay value of ~25 days][0]. This lets us set
* timers bigger than that. Its API should otherwise match `setTimeout`.
*
* [0]: https://developer.mozilla.org/en-US/docs/Web/API/setTimeout#maximum_delay_value
*/
export const setBigTimeout = (
fn: () => unknown,
delay: number | bigint,
): BigTimeout => new BigTimeout(fn, delay);
/**
* Clear a big timeout.
*/
export const clearBigTimeout = (
timeout: BigTimeout | Parameters<typeof clearTimeout>[0],
): void => {
if (timeout instanceof BigTimeout) {
timeout[clear]();
} else {
clearTimeout(timeout);
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment