Debounce and throttle are powerful techniques, but only if you really understand what they do. I often ask about them in tech interviews, and to my surprise, many developers (even seniors) struggle to explain the difference. The good news is: it’s actually quite simple. In this post, I’ll break down both techniques and share some practical use cases. If you are unfamiliar with the techniques and are asked about them too in your interview (I know, others are asking the same question in their interviews) you came to the right place!
The techniques
Debounce
Debouncing is probably the most familiar technique when it comes to controlling how often a function runs. In short, it limits the frequency of method execution, but it does a bit more than just what a setInterval
could do. Instead of calling a function immediately on every event, debounce waits until the event has stopped firing for a set period of time, and then runs it once. There’s a catch: if the event fires again within that delay, debounce resets itself and starts the timer over.
Here’s an example that fires a lot if implemented normally:
window.addEventListener("resize", () => { console.log("Resized!"); });
Every time you resize the window, this callback runs. Resize continuously and it fires dozens of times per second. If the callback does something expensive, like an XHR request or heavy calculation, your performance could suffer. Debounce solves this by executing the callback only after a certain amount of idle time in milliseconds. The same example using debounce looks like this:
const debounce = (fn, delay) => { let timeout; return (...args) => { clearTimeout(timeout); timeout = setTimeout(() => fn(...args), delay); }; }; window.addEventListener("resize", debounce(() => { console.log("Resized (debounced)!"); }, 300));
The difference is simple but powerful. While you’re actively resizing, the callback doesn’t run at all. Only 300ms after you stop resizing does the console log appear once, no matter how many resize events were fired in between. This makes debounce a perfect tool for improving performance and keeping event-driven code efficient.
Throttle
Throttling is another technique for controlling how often a function runs, but it works a bit differently than debounce. Instead of waiting for the event to stop, throttle ensures the function runs at most once every X milliseconds, no matter how many times the event fires in between. Think of it as putting a speed limit on how often your callback can execute.
Here’s an example without throttle:
window.addEventListener("scroll", () => { console.log("Scrolling!"); });
If you scroll continuously, this callback fires dozens of times per second. If the callback performs heavy operations, like updating the DOM or fetching data, your page could lag. Throttling fixes this by limiting the execution rate. Here’s a simple throttle implementation:
const throttle = (fn, limit) => { let lastCall = 0; return (...args) => { const now = Date.now(); if (now - lastCall >= limit) { lastCall = now; fn(...args); } }; }; window.addEventListener("scroll", throttle(() => { console.log("Scrolling (throttled)!"); }, 300));
The difference is subtle but important. Even if the scroll event fires continuously, the callback only runs once every 300ms, keeping your code efficient and your UI smooth. Unlike debounce, throttle doesn’t wait for the event to stop, it just spreads out the execution over time.
The difference between debounce and throttle
The key difference between debounce and throttle is how they control function execution over time. Debounce waits until an event has stopped firing for a certain period before running the function, and it resets the timer each time the event fires again. Throttle, on the other hand, ensures the function runs at regular intervals, no matter how often the event occurs, effectively spreading out the executions over time. In other words, debounce focuses on delaying until the action stops, while throttle focuses on limiting the rate of execution.
Use cases
Use cases for using debounce
- Search input: Wait until the user stops typing before firing a request to a search API, avoiding unnecessary calls.
- Window resize: Run layout recalculations or rendering updates only after the user has finished resizing the window.
- Form validation: Validate inputs only after the user pauses typing, preventing constant re-validation.
- Autocomplete suggestions: Trigger suggestion fetching once the user pauses typing rather than on every keystroke.
- Text area or editor input: Save draft content after the user stops typing, rather than on every character change.
Use cases for using throttle
- Scroll events: Limit how often a function runs while scrolling, for example updating a sticky header or a progress indicator.
- Window resize: Adjust layouts or recalculate positions at a fixed interval instead of on every pixel of resizing.
- Mouse movement tracking: Track cursor position for animations or interactions without overwhelming the system.
- Infinite scrolling / lazy loading: Check for content load positions at a controlled interval while the user scrolls.
- Rate-limited API calls: Ensure a function triggers requests at a maximum rate to prevent exceeding API limits.
I actually got asked this exact question during a tech interview last week, and I totally blanked on the difference between debounce and throttle. I remembered the general idea but couldn’t articulate it clearly under pressure. After the interview, I Googled it right away and ended up here, this post explains it better than any documentation I’ve seen so far. Wish I had read it a day earlier! Definitely bookmarking this one for future interviews. Thanks Jasper
This article is great, but it also made me wonder if you can’t confidently explain the difference between debounce and throttle, can you really call yourself a frontend developer? It’s not some obscure trick, it's core to writing performant frontend code.
At the examples you list window resizing in both lists. What do you suggest for my use case: I want to reposition my chat widget. My guess is debounce, since it is after resizing? Thanks in advance