Intermediate · JavaScript in the browser: DOM and events · topic 38 of 64 · 25 min
Timers: running code later
Explanation
Running code later with setTimeout
setTimeout(fn, ms) asks the browser to run the function fn once, after at least ms milliseconds. 1000 milliseconds is 1 second. It returns an id number. Pass that id to clearTimeout(id) to cancel it before it runs.
const toast = document.querySelector('#toast');
toast.textContent = 'Added to cart';
toast.hidden = false;
const timerId = setTimeout(() => {
toast.hidden = true; // hide the message after 3 seconds
}, 3000);
// if the user closes it early:
document.querySelector('#toast-close').addEventListener('click', () => {
clearTimeout(timerId);
toast.hidden = true;
});Repeating with setInterval
setInterval(fn, ms) runs fn again and again, every ms milliseconds, until you call clearInterval(id). A common use is a countdown, such as the "Resend OTP in 30s" text on a login page.
const resendBtn = document.querySelector('#resend');
let secondsLeft = 30;
resendBtn.disabled = true;
resendBtn.textContent = `Resend OTP in ${secondsLeft}s`;
const intervalId = setInterval(() => {
secondsLeft -= 1;
resendBtn.textContent = `Resend OTP in ${secondsLeft}s`;
if (secondsLeft === 0) {
clearInterval(intervalId); // stop the repeating timer
resendBtn.disabled = false;
resendBtn.textContent = 'Resend OTP';
}
}, 1000);| Tool | Runs | Stop it with |
|---|---|---|
| setTimeout(fn, ms) | Once, after the delay | clearTimeout(id) |
| setInterval(fn, ms) | Again and again, every ms | clearInterval(id) |
| requestAnimationFrame(fn) | Once, just before the next screen paint | cancelAnimationFrame(id) |
Debounce: wait until the user stops typing
A search box fires an input event for every letter. If you call the server for every letter of "basmati rice", that is 12 requests. Debounce means: wait until the user has stopped typing for a short time (for example 300 ms), then run once with the latest value.
function debounce(fn, wait) {
let timerId;
return (...args) => {
clearTimeout(timerId); // cancel the old plan
timerId = setTimeout(() => fn(...args), wait); // make a new plan
};
}
const search = document.querySelector('#search');
const searchProducts = debounce((text) => {
console.log('Searching for', text);
}, 300);
search.addEventListener('input', () => searchProducts(search.value));Smooth animation: requestAnimationFrame
For animation in JavaScript, use requestAnimationFrame(fn) instead of a fast setInterval. The browser calls fn just before it paints the next frame (usually 60 times a second), and pauses it when the tab is hidden. For simple effects, CSS transitions are even easier.
Why timers are not exact
A delay is a minimum, not a promise. JavaScript in a page does one thing at a time. If your code is busy with a long loop, the timer waits until it finishes. Browsers also slow down timers in background tabs to save battery, sometimes to once a minute.
Watch the lesson
Timers: running code later · 1/7
Sometimes code should run later, not now. The browser gives us timers for that.
Prefer a video by a teacher? Find free videos on “javascript settimeout setinterval debounce tutorial” on YouTube ↗
In real life: OTP login on a payment app
On a UPI or banking app login page, after you ask for an OTP, the "Resend OTP" button is disabled and shows "Resend OTP in 30s", counting down every second with setInterval. At 0 the interval is cleared and the button turns on. On the same app, the search box for contacts uses debounce, so it searches only when you pause typing.
Practice (0/3 done)
Write a function formatTime(seconds) for a countdown. It returns minutes and seconds as "m:ss". Examples: formatTime(30) is "0:30", formatTime(65) is "1:05", formatTime(0) is "0:00".
Write debounce(fn, wait). It returns a new function. Every call to the new function cancels the previous timer (clearTimeout) and starts a new one (setTimeout). When wait milliseconds pass with no new call, fn runs once with the latest arguments.
Build an "OTP login" page in your browser. It has a mobile number box, a "Send OTP" button and a "Resend OTP" button. After Send OTP, the Resend button is disabled and counts down from 30 using setInterval and your formatTime. At 0, clear the interval and enable the button. Add a search box below that logs its value with a 300 ms debounce.
Quick quiz
Read more (free)
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.