Debounce: Understand and learn how to use this essential JavaScript skill

Debounce: Understand and learn how to use this essential JavaScript skill

How to delay a function in JS - Relevant for job interviews

One essential skills of a JavaScript developer is understanding and learning how to debounce a function.

Not only is it a task you will come around in your daily work - but it is also a popular interview question.

I will explain to you what debouncing is, how it works, what the difference to throttling is and equip you with an example that will allow you to excel at your next coding interview - or in your job.

What is debounce?

Debounce basically delays the processing of a function bound to a certain user input event until a certain amount of time has passed.

In other words the function is only executed once per specific user input event, even it the event is triggered multiple times.

A well known use case for this is a search bar that gives suggestions while you type.

Here is an example from a side project of mine emojitofavicon.com, which I am currently building. It allows you to generate a favicon (a little icon you see next to the title in the browser tabs) from emojis. And you have the ability to search for thousands of emojis by using the search bar.

See how the suggestions are updating every time a new input is received (minimum 3 characters):

debounce1b.gif

This is a version without debounce, meaning the suggestions are triggered every time you type in the search bar. Later we will see a version of this with debounce implemented.

So to boil it down:

Debounce delays calling a function until a certain amount of time has passed, in which the function has not been called.

Or with an example:

Call this function only if 250 milliseconds have passed in which the function has not been called.

Why is this useful?

I told you that debouncing is an essential tool in a developer's toolkit and indeed it is very useful to improve performance, prevent duplicity and prevent unnecessary load in the back-end.

As a JavaScript developer you will have to implement it sooner or later.

Also, it is a common interview question and interviewers love to ask you to implement your own version of debounce, because it involves some intermediate and advanced concepts of JavaScript.

Most of the time it is used when dealing with user input or DOM events. Those events tend to fire very often and you definitely do not want to call a function that reacts to this thousand times per second.

Here are some common use cases:

  • Window resizing: Wait until the user is finished resizing the window, instead of triggering a function 100-1000x times
  • Search bar: Wait until the user has finished typing (or stopped for long enough), before fetching results from an API
  • Double Clicking: Prevent double clicking on buttons (Windows users know 😁)
  • Scrolling: React to scrolling events
  • Drag and drop: Improving performance (drastically) when implementing drag and drop functionality

How is debounce different from throttle?

Debounce and throttle are very similar. Both limit the execution of a function, so it is not called too often.

But throttle limits the number of times a function can be called over time.

So if you throttle a function, that would normally run 3000 times in a second to execute only once every 100 milliseconds, it will only run 10 times in a second.

Debounce however makes sure, that a certain amount of time has passed until the function is executed.

So if a user types very fast, say every 50 milliseconds and your debounce threshold is set to 500 milliseconds, 500 milliseconds after the user has stopped typing the function will be executed.

Or if he types very fast, but pauses in between for more than 500 milliseconds (for example, after finishing one word), then the function is executed as well.

How to implement debounce in JavaScript

Here is a possible implementation of the debounce function is JavaScript.

function debounce(func, delay = 250) {
    let timerId;
    return (...args) => {
        clearTimeout(timerId);
        timerId = setTimeout(() => {
            func.apply(this, args);
        }, delay);
    };
}

So how is this function working?

The debounce function is a higher-order function, meaning you can pass your own function to it and it returns a debounced version of it.

This is done by forming a closure around the function you pass into it, while storing the delay and the timer id.

Every time the debounced function is called, it sets a timeout after which the actual function is executed. Let's say the timeout is 300 ms.

It also stores the timer id, so if the debounced function is called earlier than those 300ms, the previously scheduled function will be cleared and a new execution of the function is scheduled after 300 ms.

If the debounced function is not called within the timeout, the actual function is executed. If not, the timeout is cleared and as described above the execution is scheduled again.

How to use it?

The implementation above is very easy to use.

Let's say we have a function that reacts to any kind of user input by printing into the console.

We just need to debounce this function and use the debounced version where ever we like.

function userInput(){
  console.log('User input');
}
const debouncedUserInput = debounce(userInput);

For example on a button:

<button onclick="debouncedUserInput()">User input</button>

Or on an input field:

<input type="text" id="searchBar" onkeyup="debouncedUserInput()" />

Or on a resize window event:

window.addEventListener('resize', debouncedUserInput);

And course everywhere in your JavaScript code.

Now as promised the example from above with debounce implemented:

debounce2b.gif

It has debounce implemented with a timeout of 500 ms. See how the suggestions are only displayed, after not typing for more than 500 ms.

Implementations of debounce in JavaScript libraries

Now you know how to implement and use your own debounce function.

While this knowledge is very useful, you might also want to use the debounce function implemented in famous JavaScript libraries.

Here you find the implementations of debounce in different JavaScript libraries: