Problem
Write a debounce(fn, delay) function. The returned function should:
- Wait
delayms after the LAST call before invokingfn. - Cancel any pending invocation if called again within the window.
Solution
js
function debounce(fn, delay) {
let timer;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
// Usage — search-as-you-type
const onSearch = debounce((q) => console.log("search:", q), 300);
onSearch("h"); onSearch("hi"); onSearch("hin"); // only "hin" runs
Bonus — leading edge + cancel
js
function debounce(fn, delay, { leading = false } = {}) {
let timer;
const debounced = function (...args) {
const callNow = leading && !timer;
clearTimeout(timer);
timer = setTimeout(() => {
timer = null;
if (!leading) fn.apply(this, args);
}, delay);
if (callNow) fn.apply(this, args);
};
debounced.cancel = () => { clearTimeout(timer); timer = null; };
return debounced;
}
Debounce vs Throttle
| Debounce | Throttle | |
|---|---|---|
| Behaviour | Fires once after activity STOPS | Fires at most once per N ms |
| Search-as-you-type | ✅ | ❌ (too aggressive) |
| Scroll / resize | ❌ (UI feels stuck) | ✅ |
| Submit button (prevent double-click) | ✅ (or just disable) | ✅ |
What interviewers look for
- Correct
thisandargsforwarding (useapply+ a regular function, not an arrow). - Cancellation support.
- Awareness of the leading-edge variant (fire immediately, debounce subsequent calls).
- Knowing the difference from throttle.
