Go to main content
February 9, 2021
Cover image

Before focusing on debounce and throttle methods, it’s important to know the setTimeout function.

The setTimeout function allow us to execute a callback after a specific timer. The first parameter is the callback to execute, and the second one is the minimum duration when the callback has to be executed:

// Duration in milliseconds
setTimeout(callbackToExecute, waitInMilliseconds);

Here is an example usage:

function methodToDelay() {
  console.log(
    'I will be displayed after at least 1 second',
  );
}

setTimeout(methodToDelay, 1000);

The debounce function does not execute a callback as soon as the callback is called under a specified duration time.

For example, if we want to implement an input field that makes XHR calls to a backend API, to directly filter from the database. From scratch, a call will be made for each keystroke. Most of the time, the user will type multiple letter that will result in multiple calls, but only the last will be useful. debouncing the callback will make the API call only when the user will not have type a character in less than 250ms for example.

The implementation is based on setTimeout. The execution of the callback is delayed of a duration t, and if we want to execute again the callback before this period of time, we will reset the timer.

function debounce(callback, waitTime) {
  let timeoutId;

  return function () {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => {
      callback.apply(this, arguments);
    }, waitTime);
  };
}

The throttle function allow us to execute a callback periodically as soon this one is called.

For example, if we want to execute a process when the user is scrolling, if we only do a simple handler callback on event scroll, this one will be called hundreds of times or over. For performances, it’s not the best. So we will use a throttled method to executes it every 500ms for example and gives feedback to user (if it results to a visual process).

export default function throttle(callback, waitTime) {
  let firstCallMade = false;
  let recalled = false;
  let latestContext;
  let latestArguments;

  return function () {
    function recall() {
      firstCallMade = true;
      setTimeout(() => {
        // If the function has been recalled, let's reexecute it
        if (recalled) {
          callback.apply(latestContext, latestArguments);
          recall();
          latestContext = undefined;
          latestArguments = undefined;
          recalled = false;
        } else {
          firstCallMade = false;
        }
      }, waitTime);
    }

    if (!firstCallMade) {
      // It's the first call, let's execute the function
      callback.apply(this, arguments);
      recall();
    } else {
      // The callaback has been already called once
      recalled = true;
      latestContext = this;
      latestArguments = arguments;
    }
  };
}

I have coded a little codesandbox to see the difference between this 2 methods. In this one there are:

  • the method which is immediately called
  • the method which is debounced
  • the method which is throttled

Let’s go check this here .


You can find me on Twitter if you want to comment this post or just contact me. Feel free to buy me a coffee if you like the content and encourage me.