ref – https://www.telerik.com/blogs/debouncing-and-throttling-in-javascript
Throttling
No matter what happens, we’ll let you execute only after a period of time. Yes, you may keep asking in that period of time but we’ll ignore you.
Imagine yourself as a 7-year-old toddler who loves to eat chocolate cake! Today your mom has made one, but it’s not for you, it’s for the guests! You, being spunky, keep on asking her for the cake. Finally, she gives you the cake. But, you keep on asking her for more. Annoyed, she agrees to give you more cake with a condition that you can have the cake only after an hour. Still, you keep on asking her for the cake, but now she ignores you. Finally, after an interval of one hour, you get more cake. If you ask for more, you will get it only after an hour, no matter how many times you ask her.
This is what throttling is!
Throttling is a technique in which, no matter how many times the user fires the event, the attached function will be executed only once in a given time interval.
For instance, when a user clicks on a button, a helloWorld function is executed which prints Hello, world on the console. Now, when throttling is applied with 1000 milliseconds to this helloWorld function, no matter how many times the user clicks on the button, Hello, world will be printed only once in 1000 milliseconds. Throttling ensures that the function executes at a regular interval.
Debouncing
After a certain Cooling Period, we let you execute. But only if you’re quiet during that Cooling Period.
Consider the same cake example. This time you kept on asking your mom for the cake so many times that she got annoyed and told you that she will give you the cake only if you remain silent for one hour. This means you won’t get the cake if you keep on asking her continuously – you will only get it one hour after last time you ask, once you stop asking for the cake. This is debouncing.
In the debouncing technique, no matter how many times the user fires the event, the attached function will be executed only after the specified time once the user stops firing the event.
For instance, suppose a user is clicking a button 5 times in 100 milliseconds. Debouncing will not let any of these clicks execute the attached function. Once the user has stopped clicking, if debouncing time is 100 milliseconds, the attached function will be executed after 100 milliseconds. Thus, to a naked eye, debouncing behaves like grouping multiple events into one single event.
Both throttling and debouncing can be implemented with the help of the setTimeout function. So, let’s try to understand the setTimeout function.
setTimeout
setTimeout is a scheduling function in JavaScript that can be used to schedule the execution of any function. It is a web API provided by the browsers and used to execute a function after a specified time. Here’s the basic syntax:
|
var timerId = setTimeout(callbackFunction, timeToDelay) |
The setTimeout function takes input as a callbackFunction that is the function which will be executed after the timer expires, and timeToDelay is the time in milliseconds after which the callbackFunction will be executed.
The setTimeout function returns a timerId, which is a positive integer value to uniquely identify the timer created by the call to setTimeout; this value can be passed to clearTimeout to cancel the timeout.
Example
|
function delayFuncExec() { console.log("I will be called after 100 milliseconds"); } var timerId = setTimeout(delayFuncExec, 100) console.log("Timer Id: " + timerId) |
Here, delayFuncExec will be executed after 100 milliseconds. timerId will store the integer returned by the setTimeout function.
clearTimeout
clearTimeout function is used to cancel the timeout previously established by calling the setTimeout function. clearTimeout takes the timerId returned by the setTimeout function as input and cancels its execution. So, if you want to cancel the execution of any setTimeout function, you can use clearTimeout function to cancel it by passing its timerId.
|
function delayFuncExec() { // This statement will not be printed as it will be cancelled by clearTimeout console.log("I will not be executed as I will be cancelled"); } var timerId = setTimeout(delayFuncExec, 100) console.log("Timer Id: " + timerId) clearInterval(timerId) |
Now, let try to implement throttling and debouncing using JavaScript.
Implementing Throttling in JavaScript
Throttling will change the function in such a way that it can be fired at most once in a time interval. For instance, throttling will execute the function only one time in 1000 milliseconds, no matter how many times the user clicks the button.
throttling
In the above image, we can see that when the user is scrolling, the number of scroll event is much larger than the number of times throttling executed the function. Also, throttling executed the function at regular intervals, irrespective of the number of time scroll event is fired. Let’s check the code for the throttling.
Here’s the HTML for throttling example:
throttling.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
|
<html> <style> div { border: 1px solid black; width: 300px; height: 200px; overflow: scroll; } </style> <body> <div id="div-body"> <p style="background-color: red; height: 700px">This is line 1</p> <p style="background-color: blue; height: 700px">This is line 2</p> <p style="background-color: green; height: 700px">This is line 3</p> <p style="background-color: yellow; height: 700px">This is line 4</p> </div> <p>No of times event fired</p> <p id='show-api-call-count'></p> <p>No of times throttling executed the method</p> <p id="debounc-count"></p> </body> <script src="throttling.js"> </script> </html> |
And here’s the JavaScript code for throttling example:
throttling.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
|
var timerId; var divBodyDom = document.getElementById('div-body'); // This represents a very heavy method which takes a lot of time to execute function makeAPICall() { var debounceDom = document.getElementById('debounc-count'); var debounceCount = debounceDom.innerHTML || 0; debounceDom.innerHTML = parseInt(debounceCount) + 1 } // Throttle function: Input as function which needs to be throttled and delay is the time interval in milliseconds var throttleFunction = function (func, delay) { // If setTimeout is already scheduled, no need to do anything if (timerId) { return } // Schedule a setTimeout after delay seconds timerId = setTimeout(function () { func() // Once setTimeout function execution is finished, timerId = undefined so that in <br> // the next scroll event function execution can be scheduled by the setTimeout timerId = undefined; }, delay) } // Event listener on the input box divBodyDom.addEventListener('scroll', function () { var apiCallCountDom = document.getElementById('show-api-call-count'); var apiCallCount = apiCallCountDom.innerHTML || 0; apiCallCount = parseInt(apiCallCount) + 1; // Updates the number of times makeAPICall method is called apiCallCountDom.innerHTML = apiCallCount; // Throttles makeAPICall method such that it is called once in every 200 milliseconds throttleFunction(makeAPICall, 200) }) |
The above code renders a div with a scrollbar. We have added an event listener on the scroll event. Each time the user scrolls, an anonymous function is called that prints the number of times the scroll event is fired. When the user scrolls, we want to execute the makeAPICall method. But, as this method is heavy, attaching it to a scroll event directly will cause it to fire frequently. This may cause unnecessary load on the server. To prevent this, we have used the technique of throttling.
Let’s examine the above code line by line:
When the first scroll event is fired, throttleFunction is called with the makeAPICall function and delay in milliseconds as parameters.
Inside throttleFunction, timerId is undefined, as it has not been initialized yet. So, we will go ahead and schedule the func that is themakeAPICall function using the setTimeout function. The setTimeout function will execute the func or the makeAPICall function after 200 milliseconds. Now, timerId will have the unique id of this setTimeout function.
When the second event for the scroll is fired, timerId is not undefined inside throttleFunction, so the function will return without scheduling the execution of makeAPICall. If timerId is not undefined it means that a setTimeout function has already been scheduled, hence we do not need to schedule another function.
Thus, unless and until setTimeout executes the makeAPICall function, we will not be able to schedule another makeAPICall function using setTimeout. This ensures that the makeAPICall function will be called only once in an interval.
The point to be noted is: inside the setTimeout function we have changed timerId to undefined, so once the scheduled makeAPICall function has been executed and the user again performs the scroll, throttleFunction will schedule the execution of the makeAPICall function with the help of the setTimeout function. Thus the makeAPICall function will be executed only once in a given interval.