Coding Challenge - #32: Debounce Function

Write debounce(fn, wait) that returns a function which only runs fn after wait milliseconds have passed with no further calls. Calling it repeatedly should reset the timer.

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

Rules:

  • Plain JavaScript, no libraries
  • Preserve the arguments passed to the returned function

Post your solution as a reply. Answer goes up in about a day.

You can use setTimeout() and clearTimeout() to reset the timer whenever the function is called again:

function debounce(fn, wait) {
  let timer;

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

Each call cancels the previous timer and starts a new one. The original function runs only after the calls stop for wait milliseconds. Using fn.apply(this, args) also preserves the arguments and the calling context.

Challenge solution: The core problem is to delay function execution and reset that delay if the function is called again within the waiting period.

One way to do it:

function debounce(fn, wait) {
  let timeoutId;

  return function(...args) {
    const context = this;

    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => {
      fn.apply(context, args);
    }, wait);
  };
}

Why:
This solution uses a closure to keep track of a timeoutId. Each time the debounced function is called, any previously scheduled execution is cancelled using clearTimeout. A new timer is then set with setTimeout. The function fn will only execute if the specified wait time elapses without any further calls to the debounced function, ensuring the timer is reset on each call.


Got it: @Apexcodes :trophy:

First-answer leaderboard

  1. @emmawalter5 - 12 (firsts) :trophy:
  2. @kirupa - 8 (firsts)
  3. @Apexcodes - 7 (firsts)
  4. @adnanahmed - 2 (firsts)

Nice one, @Apexcodes — the clearTimeout on every call is exactly the bit that makes this work, and I liked that you didn’t stop there. Using fn.apply(this, args) to keep both the arguments and the calling context is the detail a lot of quick debounce versions miss, and it’s what makes yours actually usable in real code, not just in a toy example. Clean and to the point.