Debounce vs Throttle: Differences, Use Cases, and Implementations
Interview-ready guide to debounce vs throttle: how they work, when to use each, and clean JavaScript implementations (with leading/trailing options).
Frontend Interview Team
February 08, 2026
Debounce and throttle are common interview questions because they show whether you understand:
- performance in the browser
- event handling
- timing control
They’re also extremely practical.
30‑second interview answer
Debounce delays execution until events stop firing for X ms (great for search input). Throttle runs at most once every X ms (great for scroll/resize). Debounce reduces calls by waiting for a pause; throttle reduces calls by enforcing a max rate.
Key points
- Debounce = “wait for quiet”.
- Throttle = “limit the rate”.
- Decide based on whether you want the final value or continuous updates.
1) The difference (one-liner)
- Debounce: “Only run after the event stops firing for X ms.”
- Throttle: “Run at most once every X ms.”
2) When to use Debounce
Use debounce when you want the final result after the user pauses:
- search input (typeahead)
- resizing a window (final layout calc)
- autosave after typing stops
Example
input.addEventListener('input', debounce((e) => {
search(e.target.value);
}, 300));3) When to use Throttle
Use throttle when you want updates during continuous activity, but not too frequently:
- scroll events (infinite scroll)
- mousemove (dragging)
- analytics pings
Example
window.addEventListener('scroll', throttle(() => {
trackScroll();
}, 200));4) Debounce implementation (simple)
export function debounce(fn, delay = 300) {
let timer;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, args);
}, delay);
};
}Interview notes
- we clear the previous timer
- only the last call survives
thisand args are preserved viaapply
5) Throttle implementation (simple)
export function throttle(fn, interval = 200) {
let lastTime = 0;
return function (...args) {
const now = Date.now();
if (now - lastTime >= interval) {
lastTime = now;
fn.apply(this, args);
}
};
}This is a "leading" throttle (runs immediately on first trigger).
6) More complete versions (leading/trailing)
Interviewers sometimes ask for options.
Debounce with leading option
export function debounceAdvanced(fn, delay = 300, { leading = false } = {}) {
let timer;
let invoked = false;
return function (...args) {
if (leading && !invoked) {
fn.apply(this, args);
invoked = true;
}
clearTimeout(timer);
timer = setTimeout(() => {
invoked = false;
if (!leading) fn.apply(this, args);
}, delay);
};
}Throttle with trailing call
export function throttleAdvanced(fn, interval = 200) {
let lastTime = 0;
let timer;
let lastArgs;
let lastThis;
return function (...args) {
const now = Date.now();
lastArgs = args;
lastThis = this;
const remaining = interval - (now - lastTime);
if (remaining <= 0) {
clearTimeout(timer);
timer = undefined;
lastTime = now;
fn.apply(lastThis, lastArgs);
return;
}
// schedule a trailing call
if (!timer) {
timer = setTimeout(() => {
lastTime = Date.now();
timer = undefined;
fn.apply(lastThis, lastArgs);
}, remaining);
}
};
}7) Common interview Q&A
Q: Is debounce or throttle better for search input?
- Debounce. You typically want the final value after the user pauses typing.
Q: What about scroll handler?
- Throttle. You want periodic updates while scrolling.
Q: Can you debounce a promise-returning function?
- Yes, but you should decide what happens to previous pending promises (often you cancel with AbortController).
Summary checklist
- I can define debounce vs throttle.
- I know when to use each (search vs scroll).
- I can explain leading vs trailing.
- I can implement both.
Summary
- Debounce = run after quiet period.
- Throttle = run at most once per interval.
- Both are used to protect performance on hot events like input/scroll/mousemove.