$ snippet debounce-throttle
Debounce and throttle
Limit how often a function runs: debounce waits for a pause in calls, throttle guarantees at most one call per interval.
/** Run `fn` only after `wait` ms have passed with no new calls. */
function debounce(fn, wait = 200) {
let t;
const debounced = (...args) => {
clearTimeout(t);
t = setTimeout(() => fn(...args), wait);
};
debounced.cancel = () => clearTimeout(t);
return debounced;
}
/** Run `fn` at most once per `wait` ms; the last call in a burst is flushed. */
function throttle(fn, wait = 200) {
let last = 0, t, pending;
return (...args) => {
const now = Date.now();
const remaining = wait - (now - last);
pending = args;
if (remaining <= 0) {
clearTimeout(t); t = undefined;
last = now; fn(...pending);
} else if (!t) {
t = setTimeout(() => { last = Date.now(); t = undefined; fn(...pending); }, remaining);
}
};
}How it works
Use debounce for things that should happen once the user stops — search-as-you-type, auto-save, window resize layout. Use throttle for things that should keep happening during continuous input, just less often — scroll position updates, drag handlers, progress reporting.
Gotchas
- Debounce delays the first call too. If you need immediate feedback plus a trailing call, run
fnonce on the leading edge before starting the timer. - Creating the debounced function inside a React render creates a new one every render. Wrap it in
useMemo/useRef. - Both preserve the latest arguments, but not
this; use arrow functions or bind if you need it.
Ad slot