Coding problem · Medium · Async & Concurrency
Implement debounce()
Medium Language practicals Most askedSeen at Meta, Uber, Atlassian, Airbnb
Implement debounce(fn, waitMs). It returns a new function that, when called repeatedly, invokes fn once, waitMs after the last call, with the last call's arguments and the same this.
The returned function also has a cancel() method that drops any pending invocation.
Typical uses: search-as-you-type, window resize handlers, autosave.
Hints
Hint 1
Keep the timer id in a closure; every call clears the previous timer and starts a new one.
Hint 2
Use a regular function (not an arrow) for the wrapper so you can capture this.
Write and run your solution
Loading the editor… (JavaScript is required to run code in your browser.)
Solution and explanation
Show the solution
Time O(1) per call · Space O(1)
A closure holds the pending timer. Each call clears it and schedules a new one, so only the final call in a burst survives. The wrapper is a normal function so this is whatever the caller used; the arrow function inside the timer keeps that this for fn.apply.
Interviewers often follow up with throttle (run at most once per interval), a leading option (fire on the first call), and flush().
Reference solution
function debounce(fn, waitMs) {
let timer = null;
function debounced(...args) {
clearTimeout(timer);
timer = setTimeout(() => {
timer = null;
fn.apply(this, args);
}, waitMs);
}
debounced.cancel = () => {
clearTimeout(timer);
timer = null;
};
return debounced;
}
Common mistakes
- Using an arrow function for the returned wrapper —
thisis lost. - Forgetting to pass the latest arguments.
- Not clearing the timer in
cancel().
Follow-up questions
- Implement throttle.
- Add
{ leading: true }support. - Return a promise that resolves with fn's result.