Skip to content
  • Timers & Cancellation · JavaScript

Timers & Cancellation

LearnViaNotes @learnvianotes· 2 min read

setTimeout, setInterval, setImmediate, queueMicrotask and AbortController — scheduling work and cancelling it.

APISchedulesCancel with
setTimeout(fn, ms, ...args)Once, after at least msclearTimeout(id)
setInterval(fn, ms)Repeatedly every msclearInterval(id)
setImmediate(fn) (Node)Once, in the check phaseclearImmediate(id)
queueMicrotask(fn)As a microtask—
requestAnimationFrame(fn) (browser)Before the next repaintcancelAnimationFrame(id)
JavaScript
const id = setTimeout(() => console.log("never printed"), 10);
clearTimeout(id);

setTimeout((a, b) => console.log("args:", a, b), 5, "x", "y");

let n = 0;
const iv = setInterval(() => {
  n++;
  console.log("tick", n);
  if (n === 3) clearInterval(iv);
}, 5);
Output
args: x y
tick 1
tick 2
tick 3

Delays are minimums

  • The callback runs at least ms later — later if the stack is busy.

  • Browsers clamp nested timers (5+ levels deep) to ≥ 4 ms and throttle background tabs to ≥ 1 s.

  • setInterval does not wait for slow callbacks; prefer a recursive setTimeout when each run must finish before the next is scheduled.

JavaScript
const start = performance.now();
setTimeout(() => {
  console.log("waited at least 20ms:", performance.now() - start >= 20);
}, 10);
while (performance.now() - start < 20) {}   // block the thread for 20ms
Output
waited at least 20ms: true

Promise-based timers

JavaScript
import { setTimeout as sleep } from "node:timers/promises";
const sleepAnywhere = (ms) => new Promise((r) => setTimeout(r, ms));   // browser version

console.log(await sleep(5, "node timers/promises"));
await sleepAnywhere(5);
console.log("slept");
Output
node timers/promises
slept

Cancellation with AbortController

JavaScript
function cancellableDelay(ms, { signal } = {}) {
  return new Promise((resolve, reject) => {
    if (signal?.aborted) return reject(signal.reason);
    const id = setTimeout(resolve, ms, "finished");
    signal?.addEventListener("abort", () => {
      clearTimeout(id);
      reject(signal.reason);
    }, { once: true });
  });
}
const controller = new AbortController();
setTimeout(() => controller.abort(new Error("user cancelled")), 10);
try {
  await cancellableDelay(1000, { signal: controller.signal });
} catch (e) {
  console.log(e.message);
}
try {
  await cancellableDelay(1000, { signal: AbortSignal.timeout(10) });
} catch (e) {
  console.log(e.name);
}
Output
user cancelled
TimeoutError

Why might setTimeout(fn, 0) not run immediately?

Free for students and teachers

Write notes like this one

Cards for every idea, quizzes and flashcards, read aloud — on the web and your phone.

Something wrong with this note? Open it to report