In my previous article, I talked about throttling
. This time, we will look at the debounce
function and how it differs from throttling
.
Using debounce
, the function will be executed only when a certain amount of time has passed since the last function call. The delay starts again with each new call.
For instance, if you set a debounce with a time of 100 ms to the onscroll
event, then the function will be executed 100 ms after the scroll stops.
Another example of using debounce
is sending AJAX requests to the server. Let's say there is a search field on the website and you need to send requests after the user enters a request, and at the same time, limit the sending of requests for each character pressed.
In this case, you can use debounce
, and set the time interval after which the request will take place. For example, by setting 1000 ms, the request will occur only after the pressing speed has exceeded 1 second.
Schematically, it can be displayed in the following way:
Just to compare, I’ll duplicate the throttling
scheme from the previous article:
Many JavaScript libraries such as lodash, underscore, and rxjs provide debounce
and throttle
methods with various additional features. Below you can view an implementation of the debounce
method:
const debounce = function debounce(fn, time) {
let timeout = null;
return function () {
const context = this;
const args = arguments;
const later = () => {
fn.call(context, ...args);
clearTimeout(timeout);
timeout = null;
}
clearTimeout(timeout)
timeout = setTimeout(later, time);
}
}
Debounce
is a higher-order function that takes 2 arguments: a main function and a timer. You can learn more about higher-order functions in our series of articles about functional programming.
Each function call updates the timer. When the timer expires, the function is executed. For instance, let's write a simple window resize event handler, just like we did in the throttling
article:
const handleResize = () => {
const { innerHeigh, innerWidth } = window;
console.log({ innerHeigh, innerWidth });
}
window.addEventListener('resize', handleResize)
Let's wrap the handler in the debounce function, and then make sure that the function is called only once:
const handleResize = () => {
const { innerHeigh, innerWidth } = window;
console.log({ innerHeigh, innerWidth });
}
const handleResizeDebounced = debounce(handleResize, 500);
window.addEventListener('resize', handleResizeDebounced);
The above example makes almost no sense in practice. The main thing is to understand the logic, and that the purpose of the debounce
and throttle
functions are to reduce the load on the browser by reducing the number of calls.
General debounce
use cases are as follows:
Browser window resizing: Let's say that when resizing the browser window, some dynamic elements are redrawn, which ends up with complex calculations in many cases, so here we can take advantage of both throttle
and debounce
.
The debounce
optimization will be more significant since the function call will only take place when the user has finished resizing the browser window; while with throttle
, the passed function will fire in the process of resizing after a given timeout.
Reducing the number of AJAX requests: For instance, when entering a request in a search field, use the debounce
function in the corresponding event handler with a delay of 200 milliseconds.
Thus, the request will not be sent to the server after each letter is entered but will be sent once after the user stops entering a query and only after 200 milliseconds.
If you need the function to be executed at a certain frequency during any action (resize, scroll, keydown), use throttle
If you need to call a function at the end of some action, it’s better to use debounce
If a function call is required at the beginning of an action, then we use debounce
with an additional immediate call parameter
This article describes how the throttle
and debounce
functions work and how to use them.
You may not fully understand the logic of the throttle
and debounce
functions at first, but it will be a huge advantage to use these functions during development, as this reduces the load on the browser, and therefore on the user's device.