JavaScript Interview Question: Implement debounce

A
Author
02 May, 2026 1 min read 670 views

Task: write debounce(fn, wait) that returns a function which only calls fn after it stops being called for wait milliseconds. Typical use: search-as-you-type.

Solution

function debounce(fn, wait) {
  let timer;
  return function (...args) {
    clearTimeout(timer);                         // cancel the previous pending call
    timer = setTimeout(() => fn.apply(this, args), wait);
  };
}

const onSearch = debounce((q) => fetchResults(q), 300);
input.addEventListener('input', (e) => onSearch(e.target.value));

Points to mention

  • The closure keeps timer between calls.
  • A regular function (not an arrow) for the returned wrapper, so this is whatever the caller used; apply passes it on with the latest arguments.
  • Only the last call's arguments are used.

Follow-up: add cancel and flush

function debounce(fn, wait) {
  let timer, lastArgs, lastThis;
  function debounced(...args) {
    lastArgs = args;
    lastThis = this;
    clearTimeout(timer);
    timer = setTimeout(() => { timer = undefined; fn.apply(lastThis, lastArgs); }, wait);
  }
  debounced.cancel = () => { clearTimeout(timer); timer = undefined; };
  debounced.flush = () => {
    if (timer === undefined) return;
    debounced.cancel();
    fn.apply(lastThis, lastArgs);
  };
  return debounced;
}

Follow-up: debounce vs throttle

Debounce waits for a pause and runs once at the end (search input, autosave). Throttle runs at most once per interval during continuous activity (scroll, resize, mousemove).

Was this article helpful?

Comments

No comments yet. Have a question or a tip? Be the first to share it.

Leave a comment

Comments are reviewed before they appear.