Understanding JavaScript Debounce vs Throttle for Better App Efficiency

Varun Kelkar - May 27 - - Dev Community

Introduction

In the fast-paced world of web development, performance and efficiency are paramount. When building interactive applications, it's common to encounter events that fire frequently, such as window resizing, scrolling, or user input. Without proper handling, these events can lead to performance issues and a poor user experience. This is where debounce and throttle come into play.

Debounce and throttle are two essential techniques that help optimize event handling by controlling the rate at which functions are executed. While they both serve to improve performance, they do so in distinct ways, each suited to different scenarios.

In this blog, we'll dive deep into the concepts of debounce and throttle, explore their differences, and provide practical examples to help you implement these techniques in your JavaScript projects.

What is Throttle?

Throttle is a technique used in JavaScript to control the rate at which a function is executed. When an event occurs frequently, such as scrolling, resizing, or mouse movements, invoking a function for every single event can lead to performance bottlenecks.

Throttling helps manage this by ensuring that the function is only called at most once in a specified period, regardless of how many times the event is triggered.

Understanding the use case for throttle

Let's understand throttle with an example.

Image description

Let's assume you have a webpage like this.

You can type your input into search box & grid will render matching results.

Additionally, you can click the Refresh button to refresh grid data. This will trigger GET API call.

Now what if user keeps on clicking on Refresh button? It will trigger countless API calls & will lead to bad performance of webpage. At one point it may even crash.

This is where we can use throttle. Using throttle, we can limit the number of times the Refresh function is called.

This is how throttle looks like,

Image description

Once user clicks Refresh button, we call the refresh function & then block the refresh function from getting called again until certain time has passed let's say 300ms.

This way we can reduce the network calls & improve the performance.

How does throttle function look like?

Let's try to write our own throttle function.

function throttle(functionToCall, limit = 200){
    // Initially we want to call the `functionToCall`
    // Hence default value is set to true.
    let hasIntervalPassed = true;
    return function(...arguments){
        const context = this;
        const args = arguments;
        // Once the function is called, 
        // we now want to block the function call & set the limit
        if(hasIntervalPassed){
             // We're using `apply` because
             // 1] It can access context 
             // 2] Multiple arguments can be passed easily.
             functionToCall.apply(context, args);
             hasIntervalPassed = false;
        } 
        setTimeout(function(){
          // Once the interval has passed, 
          // we want to allow `functionToCall` to be called.
          hasIntervalPassed = true;
        }, limit);
    }
}

// Let's assume our button has id `my-custom-button`
const myButton = document.getElementById('my-custom-button');
function buttonClick (event) {
    // handle api call here
} 
myButton.addEventListener('click', throttle(function(event) {
  buttonClick(event);
}, 500))
Enter fullscreen mode Exit fullscreen mode

This covers a very basic implementation of throttle function.

If you wish to use a more professional version, checkout Lodash Throttle.

It's a production ready & well-tested function.

What is Debounce?

Debounce is a technique used in JavaScript to limit the rate at which a function is executed. When an event triggers frequently, debounce ensures that the function runs only after a specified period of inactivity. This means the function will only be called once the event has stopped firing for a certain amount of time.

Understanding the use case for debounce

Lets take the same webpage as above

Image description

Let's say you have this webpage.

You want to search some data in the grid.

Let's assume a Search API call is invoked when anything is typed into search input. Now do we need to call Search API when for every keystroke? Will anything significant be captured in the search input per keystroke?

Invoking Search API per keystroke will have lots of network calls. This will put a lot of stress on your application. It may even crash.

With debounce we wait for a certain interval of time before we make the function call.

This way we even give user enough time to type something significant & this might even increase the accuracy of Search API results.

This is how debounce looks like,

Image description

We wait till user has interacted with component. When the time interval passes without any user activity, call the function.

If user interacts with the component before the interval has passed, we reset the interval & continue to wait until interval passes without any user activity.

How does debounce function look like?

Let's try to write our own debounce function.

function debounce(functionToCall, interval = 200){
    let timeOutId;
    return function(...arguments){
        // We keep storing all the arguments when user is interacting
        // When the user interaction stops for mentioned interval,
        // We call the function with these arguments
        const context = this;
        const args = arguments;
        // If the user keeps interacting before interval has passed,
        // We reset the interval 
        clearTimeout(timeOutId);
        // If no user activity is detected for mentioned interval,
        // We call the function
        timeOutId = setTimeout(() => {
        functionToCall.apply(context, args);
        },interval)
     };   
}

// Let's assume our search field has id `my-search-field`
const mySearchField = document.getElementById('my-search-field');
function handleSearch (event) {
    // handle api call here
} 
mySearchField.addEventListener('input', debounce(function(event) {
  handleSearch(event);
}, 2000));
Enter fullscreen mode Exit fullscreen mode

This covers a very basic implementation of debounce function.

If you wish to use a more professional version, checkout Lodash Debounce.

It's a production ready & well-tested function.

That's it folks! Hope you enjoyed the learning 😄

Go ahead! Leverage throttle & debounce in your code 🥳

. . . . .