Debounce and Throttle
Some browser events fire far more often than you need them to.
scroll, resize, and keyup on a search box can all trigger dozens of
times a second. Wiring a handler directly to one of these is a fast way to
tank performance. Debounce and throttle are the two standard fixes.

Debounce
Debounce waits for a pause in activity before running. Every new call resets the timer, so the function only fires once things go quiet — perfect for a search input where you only want to fetch after the user stops typing.
function debounce(fn, delay) {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => fn(...args), delay);
};
}
const search = debounce((query) => {
console.log('searching for', query);
}, 300);
input.addEventListener('keyup', (e) => search(e.target.value));Type "hello" quickly and search runs once, 300ms after the last
keystroke — not five times.
Throttle
Throttle guarantees a function runs at most once every n milliseconds,
no matter how often it's called. That's the right shape for a scroll
handler, where you want regular updates but not on every single pixel.
function throttle(fn, limit) {
let waiting = false;
return (...args) => {
if (waiting) return;
fn(...args);
waiting = true;
setTimeout(() => {
waiting = false;
}, limit);
};
}
const onScroll = throttle(() => {
console.log('scroll position:', window.scrollY);
}, 200);
window.addEventListener('scroll', onScroll);Which one do you want?
| Use case | Debounce | Throttle |
|---|---|---|
| Search-as-you-type | Yes | |
| Window resize recalculation | Yes | |
| Infinite scroll position tracking | Yes | |
| Button click spam prevention | Yes | |
| Drag/mousemove updates | Yes |
The pattern to remember: debounce answers "has activity stopped?", throttle answers "has enough time passed since the last run?". Pick based on whether you care about the last event or a steady stream of them.
Comments 0