DEV Community

Cover image for Understanding JavaScript Debounce vs Throttle for Better App Efficiency
Varun Kelkar
Varun Kelkar

Posted on • Updated on

Understanding JavaScript Debounce vs Throttle for Better App Efficiency

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 🥳

Top comments (16)

Collapse
 
iredox10 profile image
Idris

Thanks

Collapse
 
soumeshkundu profile image
Soumesh

that was nice. i heard about debounce and throttle and it is clear to me now

Collapse
 
dev_diaries_by_varun profile image
Varun Kelkar

Thanks Soumesh! Happy to contribute😄

Collapse
 
efpage profile image
Eckehard

Combining debounce and throttle can be most helpful to get a better user experience. Debounce events to reduce workload, but not too much to block the execution. See an implementation [here]{dev.to/efpage/better-event-throttl...}

Collapse
 
dev_diaries_by_varun profile image
Varun Kelkar

Ohh! I'll surely checkout. Thanks 😄

Collapse
 
btphuong2017 profile image
Michael Phuong • Edited

Your "throttle" function will be error in case of multiple clicks on the button at the same time.
Because it will run a setTimeout every time you click.
To avoid this error, we should put the setTimeout function in the condition hasIntervalPassed is true.
This is my opinion.

And thank for your post.

Collapse
 
dev_diaries_by_varun profile image
Varun Kelkar

@btphuong2017 Thanks for your keen observation 😄. I've corrected the code.

Collapse
 
mattlewandowski93 profile image
Matt Lewandowski

Nice article! You should update your code blocks to include the language, so it adds syntax highlighting. ‘’’javascript

Collapse
 
dev_diaries_by_varun profile image
Varun Kelkar

Ohh right!! I missed it! Thanks Matt😄

Collapse
 
lynvu99 profile image
lynvu99

New knowledge obtained, thank you

Collapse
 
dev_diaries_by_varun profile image
Varun Kelkar

Thanks!! Happy to contribute 😄

Collapse
 
ajaymanikanta1123 profile image
Guddeti Ajay Manikanta ⭐⭐⭐

Awesome article. I wish you come up with more like this.

Collapse
 
dev_diaries_by_varun profile image
Varun Kelkar

Thank you so much! @ajaymanikanta1123 😄 I'll definitely try to write more articles.

Collapse
 
joecrypt profile image
Uwagbale Joseph

thanks for this

Collapse
 
george_nwosu_c55f8d86fad0 profile image
George Nwosu

Thanks a lot; I just finished reading JavaScript Event module but I did not see such an important issue. I love it.

Collapse
 
dev_diaries_by_varun profile image
Varun Kelkar

Thanks @george_nwosu_c55f8d86fad0 😄. Glad to know😇