TL;DR: Understand the differences between JavaScript debounce and throttle to improve web app performance by reducing unnecessary API calls. Learn practical implementations and best use cases to enhance efficiency in your applications.
Performance is one of the most crucial aspects of modern web applications. As developers, we follow various techniques to enhance application performance and provide a better user experience. For example, debouncing and throttling are two simple, yet powerful techniques we can use in JavaScript applications to improve performance.
In this article, I will introduce debouncing and throttling in JavaScript, compare them, and discuss why we need to use them.
Syncfusion JavaScript UI controls are the developers’ choice to build user-friendly web applications. You deserve them too.
Why do we need to debounce and throttle?
Usually, developers have the freedom to decide when to call a function. But sometimes, they have to hand over control to users. For example, event triggers are widely used in applications to trigger functions based on events like key presses, button clicks, and mouse movements. In such situations, users can trigger those events far more than required and cause significant performance issues in the application.
For example, consider a search bar where we need to display a suggestion list as the user types. We can implement this using an event listener to bring data from the backend on each key press. However, it will negatively impact application performance, since it will make an API call each time the user presses a key.
The following code shows an example of this scenario. It will make 10 API calls if we type the word JavaScript.
// index.html
<html> <body> <label>Search Here : </label> <input type="text" id="search-bar" /> </body> </html>
// index.js
var searchBarDom = document.getElementById('search-bar'); var numberOfKeyPresses = 0; var numberOfApiCalls = 0; function getSearchResult() { numberOfApiCalls += 1; console.log('Number of API Calls : ' + numberOfApiCalls); } searchBarDom.addEventListener('input', function (e) { numberOfKeyPresses += 1; console.log('Search Keyword : ' + e.target.value); console.log('Number of Key Presses : ' + numberOfKeyPresses ); getSearchResult(); });
You can find a working example of this code in StackBlitz.
As you can see, there is a significant number of unnecessary API calls in the previous example. In such situations, we can use debouncing and throttling to reduce the number of API calls triggered by the user event and improve the application performance without any drag on the user experience.
So, let’s see these two techniques and how we can implement them.
Explore the best and most comprehensive JavaScript UI controls library in the market.
What is debounce?
The concept of debouncing is pretty straightforward. It delays the function invocation by a defined period of time to avoid unnecessary invocations. So, the function will only be invoked if no event is triggered within that time. If the user triggers a new event during that time, the time will be reset.
Let’s consider the previous example again. The issue with the scenario was unnecessary API calls. So, if we define a debounce function with a delay of one second, it will hold back the API call until one second passes without any user events. If the user presses a key within that second, the debounce function will reset the delay and wait for another second to make the API call.
How to implement a debounce function
We can easily implement a debounce function using the setTimeout() and clearTimeout() functions. It should also take a callback function and the delay as input parameters.
function debounce(callback, delay = 1000) { var time; return (...args) => { clearTimeout(time); time = setTimeout(() => { callback(...args); }, delay); }; }
As you can see, the debounce function acts as a wrapper for the callback function and ensures that it will be invoked after the delay. In this case, the default delay is 1,000 milliseconds.
Let’s now modify the search bar example code with a debounce function.
var searchBarDom = document.getElementById('search-bar'); var numberOfKeyPresses = 0; var numberOfApiCalls = 0; const getSearchResult = debounce(() => { numberOfApiCalls += 1; console.log('Number of API Calls : ' + numberOfApiCalls); }, 1000); searchBarDom.addEventListener('input', function (e) { numberOfKeyPresses += 1; console.log('Search Keyword : ' + e.target.value); console.log('Number of Key Presses : ' + numberOfKeyPresses); getSearchResult(); }); function debounce(callback, delay = 1000) { var time; return (...args) => { clearTimeout(time); time = setTimeout(() => { callback(...args); }, delay); }; }
Although the user has typed the word JavaScript, only a single API call has been invoked. So, debouncing has blocked nine unnecessary API calls from the previous example. You can find a working example of this code in StackBlitz.
Everything a developer needs to know to use JavaScript control in the web app is completely documented.
What is throttle?
Throttle is another technique to minimize unnecessary function invocations when using event listeners. However, throttle works a bit differently from debouncing. Instead of delaying, it invokes the callback function at regular intervals as long as the event trigger is active.
For example, assume we have defined the delay as one second in a throttle function. First, it will invoke the callback function immediately. Then, it will use the delay time as the waiting time and invoke the callback function every second until the event trigger becomes inactive.
How to implement a throttle function
We can implement a throttle function using the setTimeout() function and a flag variable. It should take a callback function and the delay as input parameters.
function throttle(callback, delay = 1000) { let shouldWait = false; return (...args) => { if (shouldWait) return; callback(...args); shouldWait = true; setTimeout(() => { shouldWait = false; }, delay); }; }
In debouncing, we implemented the debounce function as a wrapper of the callback function, since we delay the callback function invocation. But in throttle implementation, we immediately invoke the callback function if the shouldWait flag is false. Then, the setTimeout() function is used to update the flag value based on the delay we define.
The following code shows the initial search bar example optimized with a throttle function.
var searchBarDom = document.getElementById('search-bar'); var numberOfKeyPresses = 0; var numberOfApiCalls = 0; const getSearchResult = throttle(() => { numberOfApiCalls += 1; console.log('Number of API Calls : ' + numberOfApiCalls); }, 1000); searchBarDom.addEventListener('input', function (e) { numberOfKeyPresses += 1; console.log('Search Keyword : ' + e.target.value); console.log('Number of Key Presses : ' + numberOfKeyPresses); getSearchResult(); }); function throttle(callback, delay = 1000) { let shouldWait = false; return (...args) => { if (shouldWait) return; callback(...args); shouldWait = true; setTimeout(() => { shouldWait = false; }, delay); }; }
As you can see, only three API calls were made in this example when I typed the word JavaScript. The first call is the initial call, and the other two were made after 5 and 10 key presses, respectively. So, the throttle function has reduced seven unnecessary API calls. You can find a working example of this code in StackBlitz.
Syncfusion JavaScript controls allow you to build powerful line-of-business applications.
Difference between debounce and throttle
Debounce monitors the time delay between user actions and only executes the callback function if the delay exceeds the time delay defined by the developer. So, continuous user actions can significantly delay the callback function’s execution if we use debounce.
On the other hand, throttle uses the time delay to execute the callback function at regular intervals until the event trigger is active. So, it does not delay the callback function execution for a significant period like debounce.
When to use what
I explained both debounce and throttle using a search bar example with key press events. However, there are some specific scenarios where we should use one or the other of these techniques:
- Debounce is most suitable for control events like typing or button clicks.
- Throttle is most suitable for continuous user events like resizing and scrolling.
Easily build real-time apps with Syncfusion’s high-performance, lightweight, modular, and responsive JavaScript UI components.
Conclusion
This article discussed how we could use debounce and throttle to handle user events and minimize unnecessary function executions in JavaScript applications. Ultimately, these two techniques can significantly improve your application’s performance since they can avoid many unnecessary API calls, DB queries, and so on. So, give them a try when implementing event triggers on your next application.
Thank you for reading!
Syncfusion’s Essential JS 2 is the only suite you will ever need to build an app. It contains over 65 high-performance, lightweight, modular, and responsive UI components in a single package. Download a free trial to evaluate the controls today.
If you have any questions or comments, you can contact us through our support forums, support portal, or feedback portal. We are always happy to assist you!