2. Implement debounce(fn, wait) — Frontend Interview Question

medium

You will be asked this. The trap is that a 4-line version works for the obvious test, but interviewers probe the edges.

Minimum viable answer

function debounce(fn, wait) {
  let timer;
  return function (...args) {
    clearTimeout(timer);
    timer = setTimeout(() => fn.apply(this, args), wait);
  };
}

Three things to call out as you write this:

  1. function not arrow — so this binds to the caller. Matters for el.addEventListener("scroll", debounce(handler, 100)).
  2. apply(this, args) — preserves the original this and arguments.
  3. One timer per closure — multiple debounced functions don't share state.

The follow-ups interviewers love

  • "How would you add a cancel method?" → attach result.cancel = () => clearTimeout(timer).
  • "What if I want it to fire on the leading edge?" → add a { leading: true } option; on first call, fire immediately and set a flag.
  • "Difference from throttle?" → debounce defers until quiet; throttle fires at most once per window.

What to practice

Try the editor on the right. Write debounce, then add a cancel method without re-instantiating the timer. If you can do both in under five minutes, you're ready for this question in a real interview.

More questions

index.js
function debounce(fn, wait) {
  // your code here
}

// Try it:
const log = debounce((x) => console.log('called with', x), 300);
log(1); log(2); log(3);
// Only "called with 3" should print after 300ms.

Tests

Test Code

Enter JavaScript that runs after your solution. It should return a value or a Promise.