Timers: setTimeout & setInterval

Timers schedule code to run later: once after a delay with setTimeout, or repeatedly with setInterval. They power countdowns, auto-saving, polling, notifications that fade away, and the debounce and throttle techniques that keep busy pages responsive.

setTimeout

JS timeout.js
console.log("Ordering…");

const id = setTimeout(() => {
  console.log("Your coffee is ready");
}, 100);

console.log("You can do other things while you wait");
Output
Ordering…
You can do other things while you wait
Your coffee is ready

setTimeout(callback, ms) runs the callback once, after at least ms milliseconds, and returns an ID. The code after it doesn't wait — that's what makes timers asynchronous. (In browsers the ID is a number; in Node.js it's an object, though it works the same way.)

Extra arguments are passed to the callback: setTimeout(greet, 1000, "Ana") calls greet("Ana").

Cancelling with clearTimeout

JS clear.js
const reminder = setTimeout(() => console.log("This never prints"), 100);
clearTimeout(reminder);
console.log("Reminder cancelled");
Output
Reminder cancelled

setInterval

setInterval runs a callback repeatedly, every ms milliseconds, until you stop it with clearInterval:

JS interval.js
let remaining = 3;

const timer = setInterval(() => {
  console.log(remaining);
  remaining--;
  if (remaining === 0) {
    clearInterval(timer);
    console.log("Liftoff!");
  }
}, 50);
Output
3
2
1
Liftoff!

A live countdown

Try it yourself
Result

Notice the countdown computes the time remaining from a fixed end time rather than counting ticks. Timer delays are a minimum, not a guarantee — browsers slow timers in background tabs, and a busy page delays them — so counting ticks drifts.

Timers don't pause your code

Even a delay of 0 waits until the current code finishes:

JS zero.js
setTimeout(() => console.log("timeout 0"), 0);
for (let i = 0; i < 3; i++) console.log("loop", i);
Output
loop 0
loop 1
loop 2
timeout 0

Lesson 51 explains why: timer callbacks wait in a queue until the call stack is empty.

Recursive setTimeout

An alternative to setInterval is a setTimeout that schedules the next run when it finishes. This guarantees a gap between runs, even if each run takes a while — ideal for polling a server:

JS recursive.js
let checks = 0;

function poll() {
  checks++;
  console.log(`check #${checks}`);
  if (checks < 3) setTimeout(poll, 50);
}

poll();
Output
check #1
check #2
check #3

Debounce

A search box shouldn't send a request on every keystroke. Debouncing waits until the user stops typing for a moment:

Try it yourself
Result

Every keystroke cancels the pending timer and starts a new one, so the search only runs once typing pauses for 400 ms. This is a closure in action (lesson 26).

Throttle

Throttling limits a function to run at most once per time window — useful for scroll and resize handlers that would otherwise fire dozens of times a second:

JS throttle.js
function throttle(fn, wait) {
  let last = 0;
  return (...args) => {
    const now = Date.now();
    if (now - last >= wait) {
      last = now;
      fn(...args);
    }
  };
}

let runs = 0;
const onScroll = throttle(() => runs++, 1000);
for (let i = 0; i < 100; i++) onScroll();
console.log(`called 100 times, ran ${runs} time(s)`);
Output
called 100 times, ran 1 time(s)

requestAnimationFrame

For animations, use requestAnimationFrame(callback) instead of timers. It runs right before the browser paints the next frame (usually 60 times a second), pauses in background tabs, and produces smoother motion:

Try it yourself
Result