‘Debounce’ vs ‘Throttle’ Explained Visually (with JS Code)
Debounce and throttle are two commonly used techniques in JavaScript to control how often a function is executed over time. They are particularly useful in high-frequency events like scroll, mousemove, or keyup. In this post, we’ll break down the differences between debounce and throttle with interactive demos and in-depth code explanations.
By the end of this article, you’ll not only understand how they work, but also when and why to use each. Let’s get started.
1. What Are Debounce and Throttle?
Before jumping into code, it’s important to grasp the goal of each technique:
- Debounce: Ensures a function is only called after a specified time has passed since the last event. It’s useful for events that trigger rapidly, but where we only care about the final result (like a search field).
- Throttle: Ensures a function is called at most once every specified interval. Useful for continuous events like
scrollorresize, where you want periodic updates.
2. Debounce Explained with Typing
Let’s look at an example using debounce with a search input. We simulate an API call when a user stops typing for 500 milliseconds:
function debounce(func, delay) {
let timeoutId;
return function(...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => func.apply(this, args), delay);
};
}
const searchInput = document.getElementById('search');
function handleSearchInput(event) {
console.log('Sending API request for:', event.target.value);
}
searchInput.addEventListener('input', debounce(handleSearchInput, 500));
How it works:
- Every keystroke resets the timer.
- The function is only called if typing has stopped for 500ms.
Use case: Reduces the number of API calls in search bars, improving frontend and backend performance.
3. Throttle Explained with Scrolling
Now, let’s throttle a function that’s triggered by the scroll event. We want to update a progress bar no more than once every 300ms:
function throttle(func, limit) {
let inThrottle;
return function(...args) {
if (!inThrottle) {
func.apply(this, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
}
const progressBar = document.getElementById('progress');
function updateScrollProgress() {
const scrollPercent = (window.scrollY / (document.body.scrollHeight - window.innerHeight)) * 100;
progressBar.style.width = scrollPercent + '%';
console.log('Updated progress:', scrollPercent);
}
window.addEventListener('scroll', throttle(updateScrollProgress, 300));
How it works:
- The function runs immediately on the first scroll.
- Additional calls within 300ms are ignored.
Use case: Optimizes performance when responding to events that fire continuously, like resize or scroll.
4. Visual Comparison and Demo Setup
To get a better feel for the difference, create two buttons:
<button id="debounce-btn">Debounced Button</button>
<button id="throttle-btn">Throttled Button</button>
// JS Implementation
function logClick(type) {
console.log(`${type} click at`, new Date().toLocaleTimeString());
}
document.getElementById('debounce-btn')
.addEventListener('click', debounce(() => logClick('Debounced'), 1000));
document.getElementById('throttle-btn')
.addEventListener('click', throttle(() => logClick('Throttled'), 1000));
Now click spam each button and see the logs:
- Debounced: Only logs once after you stop clicking for 1 second.
- Throttled: Logs at fixed intervals while you click rapidly.
This hands-on test makes the difference crystal clear.
5. When to Use Debounce vs Throttle
Here’s a helpful table:
| Use Case | Debounce | Throttle |
|---|---|---|
| Search Input | ✅ | ❌ |
| Auto-Saving Forms | ✅ | ❌ |
| Resize Window | ❌ | ✅ |
| Scroll Events | ❌ | ✅ |
| Button Mash Limit | ✅ (Delay trigger) | ✅ (Rate limit) |
Tip: When in doubt, ask: “Do I want the last action or just spaced-out actions over time?” Go with debounce for the former and throttle for the latter.
6. Performance and Optimization Tips
Both debounce and throttle help reduce resource waste in web applications. Here are a few extra tips:
- Always debounce API-heavy interactions (search, forms).
- Combine debounce with
input[type="search"]andaria-livefor accessibility. - Avoid using
setTimeoutdirectly for timing-sensitive throttles—considerrequestAnimationFrameif animation is involved. - Popular libraries like Lodash offer
_.debounceand_.throttle—battle-tested and flexible.
Conclusion
Understanding debounce and throttle is key to writing smooth and efficient JavaScript applications. Whether you’re preventing unnecessary API calls or limiting UI rendering from scroll storms, these functions are must-have tools in your dev belt.
With the visual demos and code examples above, you should now feel confident implementing both patterns in real-world scenarios.
Happy coding!
Useful links:


