Debounce vs throttle: what's the difference?
By FrontendPro Editorial Team Updated 9/26/2026
Answer
Both limit how often a function runs when events fire rapidly, but they answer different questions.
Debounce waits for the storm to pass: run once, after the events stop for N milliseconds. Every new event resets the timer.
Throttle enforces a steady rhythm: run at most once every N milliseconds, no matter how many events arrive.
function debounce(fn, delay) {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => fn(...args), delay);
};
}
function throttle(fn, interval) {
let last = 0;
return (...args) => {
const now = Date.now();
if (now - last < interval) return;
last = now;
fn(...args);
};
}
Fire an event every 100 ms for one second, with a 300 ms setting:
- Debounced — runs once, 300 ms after the last event. Total: 1 call.
- Throttled — runs roughly every 300 ms while events continue. Total: ~4 calls.
Choosing between them
Use debounce when only the final state matters: a search box that should query after typing stops, validating a field on blur, saving a draft, or reacting to a window resize once it settles.
Use throttle when you need regular updates during a continuous action: scroll position handlers, mousemove tracking, progress indicators, or rate-limiting requests to an API.
The wrong choice is noticeable. Debouncing a scroll handler means nothing updates until the user stops scrolling; throttling a search box means firing requests mid-word.
In production, requestAnimationFrame is often a better throttle for anything that touches layout, and libraries like Lodash add options such as leading/trailing edge control and cancellation.
