Two functions run code later. They are provided by the browser (and Node.js).
setTimeout: once, after a delay
setTimeout(() => {
console.log("Runs after 500 ms");
}, 500);
console.log("Runs immediately");
The delay is in milliseconds. setTimeout does not pause the program. It schedules the function and returns right away.
Passing arguments
function greet(name) {
console.log("Hello, " + name);
}
setTimeout(greet, 200, "Maya"); // extra arguments go to the function
Cancelling
setTimeout returns an id. Use clearTimeout(id) to cancel before it runs.
const id = setTimeout(() => console.log("never printed"), 500);
clearTimeout(id);
console.log("cancelled");
setInterval: repeat
let count = 0;
const timer = setInterval(() => {
count++;
console.log("tick", count);
if (count === 3) {
clearInterval(timer); // stop it!
console.log("done");
}
}, 200);
An interval keeps running forever until you call clearInterval. Forgetting to stop it is a common memory and CPU leak.
A live clock
<p id="clock"></p>
<script>
const clock = document.querySelector("#clock");
function update() {
clock.textContent = new Date().toLocaleTimeString();
}
update();
setInterval(update, 1000);
</script>
Timers are not exact
The delay is a minimum. If the page is busy, the callback waits. Browsers also slow timers in background tabs. Do not use setInterval to measure time. Compare timestamps (Date.now()) instead.
The “zero delay” trick
setTimeout(fn, 0) runs fn as soon as the current code finishes, not immediately.
console.log("A");
setTimeout(() => console.log("C"), 0);
console.log("B");
// the order is A, B, C
This surprises people, and it is a good way to see how the event loop works: The Event Loop.
Animations
For visual animation, use CSS or requestAnimationFrame(), which syncs with the screen and pauses in hidden tabs. Timers are the wrong tool.
Promise wrapper
A tiny helper turns setTimeout into something you can await:
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
wait(300).then(() => console.log("waited"));
You will use this throughout the chapter.
Calling instead of passing
setTimeout(doWork(), 1000) runs doWork now and schedules its result. Write setTimeout(doWork, 1000) or setTimeout(() => doWork(), 1000).