A recursive timer schedules the next setTimeout() from inside the current callback. Unlike setInterval(), this makes it easier to wait until one run finishes before scheduling the next.
function repeat() {
console.log("run");
setTimeout(repeat, 1000);
}
repeat();
With setInterval(), the next callback is scheduled according to the interval even if previous work is slow. A recursive timeout schedules only after your callback reaches the scheduling line, so you can control when the next run begins.
let timerId;
function tick() {
document.getElementById("output").textContent = new Date().toLocaleTimeString();
timerId = setTimeout(tick, 1000);
}
tick();
See the existing recursive timer demo.
clearTimeout(timerId);
Store the most recently returned timeout ID. See clearTimeout and resetting timers.
async function poll() {
try {
await refreshData();
} finally {
timerId = setTimeout(poll, 5000);
}
}
poll();
This avoids starting the next refresh while the previous refresh is still running.
let delay = 1000;
function repeat() {
console.log(delay);
delay = Math.min(delay * 2, 8000);
timerId = setTimeout(repeat, delay);
}
This pattern can implement a simple backoff strategy.
setTimeout() specifies a minimum delay. Browser scheduling, background-tab throttling, and long tasks can make the actual delay longer. If a display must reflect real elapsed time, calculate from timestamps rather than incrementing a counter and assuming each callback arrived on time.
setTimeout(repeat(), 1000) instead of passing the function.Related: real-time clock.
Author & Instructor at plus2net
I write and maintain practical tutorials on Python, PHP, SQL, JavaScript, HTML, jQuery, and web development at plus2net. The tutorials focus on clear explanations, working examples, and code that readers can test and adapt while learning.