How throttle and debounce timing functions can optimize your script performance

In JavaScript, timing functions like throttle and debounce give developers control over the rate at which a function is called. Timing functions are now considered as one of the fundamental techniques that every web developer must know. By controlling how often an event is called, they have a significant effect on the performance of scripts. Timing functions are especially useful when working on event handler assignments. 

As developers, we have to deal with variousand sometimes unforeseenscenarios while coding. A lot of times, we might have to invoke functions even when it’s not necessary. Consider a scenario where you want to execute a callback for resizing a window. Does it make sense to fire the callback as you resize? Most likely not. You should wait until the user has finished interacting with the tool, and then fire the callback. This might seem like common sense but as the complications increase, it might be a tall task to execute this without using timing functions.

Considering that there is still a lot of confusion around the concepts of  debouncing and throttling (including where to use it, and how it works), I have simplified these concepts in this blog so that you can optimize the performance of your scripts with ease.

How throttle and debounce timing functions differ

Throttle and debounce are both timing functions that limit the number of function calls. The difference lies in the way they operate.

Throttle: When there is a continuous function call, throttle runs a given function just once in a given period.

Throttle is useful for cases where users carry out a smooth or continuous event, such as scrolling or resizing. In the event of animating elements based on their scroll position or handling an infinite scroll page, we can use throttle to control how often the scroll handler is called.

throttle function

Debounce: When there is a continuous user event call, debounce calls a function when a user hasn’t carried out an event in a specific amount of time.

Debouncing is a good method for controlling events that require sporadic user actions, such as keying in an input field or clicking a button. In the case of a search bar that makes API calls according to user input, implementing a debounce is a good way to reduce the number of calls made to the API.

The following video snippet displays how you can see as many API calls on each keypress without using the debounce function.

The following video snippet shows how you can perform just a few API calls with debounce to get the same results.

 

Why we use throttle and debounce timing functions

Timing functions are used to protect resources while improving their performance. Throttle and debounce allows you to  call a function fewer times than you would in a storm of events. Debounce and throttle are two methods for optimizing performance of scripts by controlling how often an event is called.

In Freshdesk Messaging, we have used these two techniques in various places to improve user experience and product performance.

Here, I would like to share one of the scenarios where we use the debouncing logic. In the Freshdesk messaging tool, we have an inbox where agents can send and receive messages. Agents can highlight placeholders in the editor so that when they send the message, the system replaces the placeholder with the actual message.  

Previously, we would check for regular expression (regex) matches on each keypress in the editor to identify and highlight if the content was a placeholder. On each keypress, the system parsed  the entire content with regex to find the placeholder match. The downside to this was that regex matches on each keypress degraded the user typing experience. We also needed to highlight the content that the user typed in the placeholder at the same time. 

That was when we decided to use the debounce logic on keypress. 

Now, when a user is not typing for a few milliseconds, we call the debounce logic performing the parsing function and replace the logic. These timing functions are very useful when it comes to optimizing performance and user experience.

The following video snippet illustrates the scenario.

How you can implement your own timing functions

By using the functions, closures, call, apply, and setTimeout, in JavaScript, we’ll show how you can implement your own timing functions. 

Using the throttle timing function

const throttle = (callback, interval) => {
   let timer;
   let allowEvents = true;
    return function() {
     let context = this;
     let args = arguments;
      if (allowEvents) {
       callback.apply(context, args)
       allowEvents = false;
       clearTimeout(timer);
       timer = setTimeOut(function(){
         allowEvents = true
       }, interval)
     }
   }
 }

You can also check out an example on this CodePen link

Using the debounce timing function

const debounce = function(callback, interval) {
   let timer;
   return function(){
       clearTimeout(timer)
       timer = setTimeout(function(){
         callback.apply()
       }, interval)
    }
}

You can also check out an example on this CodePen link

Timing ahead

You should now have a better understanding of timing functions and the differences between throttling and debouncing. We’ve also explored the logical approaches and the code implementation of both of these methods so you can apply them to real-life situations and optimize the performance of your scripts.

References

  1. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures
  2. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply
  3. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call
  4. https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout