JavaScript Timers — Spot the Bug: setInterval vs setTimeout
This is a daily Javascript challenge from the CodeShot archive. Practice your knowledge of Setinterval Vs Settimeout Bug and improve your technical interview readiness.
function delay(ms, callback) {
setInterval(callback, ms)
}
delay(1000, () => console.log("done"))
Detailed Explanation
Why This Question Matters
If you've been coding in JavaScript for a while, you've probably used setTimeout and setInterval a thousand times. They seem straightforward. But there is a classic "gotcha" that trips up beginners and even catches experienced devs when they're rushing through a PR.
The confusion usually stems from the naming. Both functions deal with time, and both take a callback. But they serve fundamentally different purposes. When you're tasked with creating a "delay," your brain naturally thinks about a pause. If you accidentally use the wrong timer function, you aren't just introducing a bug—you're potentially creating a memory leak that could crash a browser tab or spike a server's CPU.
Understanding the Code
Let's look at the snippet again:
On the surface, it looks fine. You pass in 1000 milliseconds and a function that logs "done." You expect to see "done" in the console once, and then silence.
But here is what's actually happening under the hood. setInterval doesn't just wait for the time to pass and then execute the code. It tells the JavaScript engine: *"Run this function every X milliseconds until I explicitly tell you to stop."*
So, instead of a one-time delay, you've created an infinite loop. Every single second, for the rest of the application's lifecycle, that callback will fire. If that callback were doing something heavy—like fetching data from an API or manipulating the DOM—your app would quickly slow to a crawl.
Finding the Correct Answer
The goal was to run the callback once.
The correct fix is to swap setInterval for setTimeout. Here is how the corrected code looks:
Why this works:
setTimeout is designed for a single execution. It places the callback in the task queue after the specified delay, executes it once, and then it's finished. No cleanup required, no infinite loops.
Why the original failed:
The original used setInterval. As mentioned, that's a recurring timer. To make setInterval behave like a one-time delay, you would have to capture the timer ID and call clearInterval inside the callback itself. That's an absurdly over-engineered way to do something that setTimeout does by design.
Common Mistakes Developers Make
One of the biggest traps here is assuming that "delay" and "interval" are interchangeable. They aren't.
Another common mistake is forgetting that these timers are asynchronous. Beginners often write code like this:
They expect "Hello" then "World." But because JavaScript is single-threaded and uses an event loop, it doesn't "pause" the execution of the script. It schedules the timeout and moves immediately to the next line. You'll see "Hello" instantly, and "World" a second later.
Then there's the "drift" issue. Neither setTimeout nor setInterval are perfectly accurate. If the main thread is blocked by a heavy computation, your "1 second" delay might actually take 1.2 seconds. If you're building something that requires precision (like a metronome or a high-performance game engine), relying on these basic timers will lead to jitter.
Real-World Usage
In production, you rarely see a bare setTimeout used for simple delays. Instead, we usually wrap them in Promises to make them work with async/await. This makes the code read linearly and avoids "callback hell."
Here is how a professional developer would actually implement a delay utility:
This pattern is everywhere. You'll see it in integration tests (waiting for an element to appear), in API polling logic (waiting before retrying a failed request), and in UI animations.
If you actually need a recurring task—like updating a clock on a dashboard or polling a server for new messages—that's where setInterval shines. But always remember: every setInterval must have a corresponding clearInterval. If you navigate away from a page in a React or Vue app and don't clear your intervals, those functions keep running in the background, eating up memory.
Key Takeaways
- setTimeout is for "do this once after a wait."
- setInterval is for "do this repeatedly every X milliseconds."
- Mixing them up leads to infinite loops and memory leaks.
- Timers are not precise; they are scheduled, not guaranteed.
- For modern apps, wrap your timers in Promises to use async/await for cleaner, more readable code.
Why this matters
Understanding Setinterval Vs Settimeout Bug is crucial for passing technical interviews. In real-world applications, this concept often leads to subtle bugs if not handled correctly. For more details, you can always refer to the official MDN Documentation.