Skip to main content

Throttle and Debounce

Quite often, you need to handle window resizing, scrolling, mouse movement or user text input. This can be sorting a collection and rendering results, animating an element, manipulating the DOM tree, etc. All this improves UX (user experience), but, unfortunately, heavily loads the browser because event handlers are triggered too often. Such events are informally called "chatty events".

For example, if you add an event listener to scrolling, then when you scroll the page, you will call around 30 events per second. Slow scrolling (swipe) in a smartphone can trigger up to 100 events per second. If the scroll event handler does heavy computation and other DOM manipulation, you will face performance issues.

Throttle and Debounce are two similar (but different in their behavior) techniques to control how many times you allow a function to execute over time. Use their versions from the Lodash library.

Adding a library

CDN (Content Delivery Network) is a geographically spread network infrastructure that provides fast content delivery to users of web services and sites. The servers included in CDN are located in such a way as to minimize the response time for site/service users.

Let's connect the Lodash library to the project via CDN. To do this, use the cdnjs.com service and add a link to the library script at the end of the HTML document, as shown in the example.

index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document title</title>
</head>
<body>
<!-- HTML-markup -->

<!-- Lodash library script file -->
<script
async
src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"
integrity="sha512-WFN04846sdKMIP5LKNphMaWzU7YpMyCU245etK3g/2ARYbPK9Ub18eG+ljU96qKRCWh+quCY7yefSmlkQw1ANQ=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
></script>
<!-- Your script file -->
<script defer src="path/to/script.js"></script>
</body>
</html>

You can now access the library in your script. When adding libraries via CDN, a property is added to the window object, which stores what the library has provided. The name of this property is unique to the library and is described in its documents. For Lodash, this is the underscore _. To check, use the add method, which simply adds two numbers.

script.js
const result = _.add(2, 3);
console.log(result); // 5

Throttle

The throttle technique controls the number of times a function can be called in a given time interval. That is, it allows a function to be called no more than once in N milliseconds, ensuring its regular execution.

Event throttling

By using throttle, you have no control over how often the browser triggers events. You are just taking control of how often the event handler function is executed.

document.addEventListener(
"scroll",
_.throttle(() => {
console.log("Scroll handler call every 300ms");
}, 300)
);

The version from the Lodash library expects the function to be "slowed down" as the first argument, and the number of milliseconds as the second one. It returns a new function to pass to the event listener.

Debounce

The debounce technique ensures that the function will only be called if there is a pause of N milliseconds between events. For example, while the user scrolls the page, the function will not be called, but as soon as scrolling stops, the function will be called after 300 milliseconds. If scrolling resumes earlier than 300 milliseconds after the pause, the function will not be called.

Trailing edge debounce

By using debounce, you do not control how often the browser generates events, but just take control over the execution frequency of the event handler function.

document.addEventListener(
"scroll",
_.debounce(() => {
console.log("Scroll handler call after 300ms pause");
}, 300)
);

The version from the Lodash library expects the function as the first argument, and the number of milliseconds as the second one. It returns a new function to pass to the event listener.

debounce method modes

By default, the debounce method works in the mode calling the function N milliseconds after a pause between event streams. This mode is called trailing edge (at the end). There are tasks when a function must be called immediately after the first event in the stream has occurred, followed by ignoring all subsequent events, until a pause between them, for example, 300 milliseconds. At the start of the next stream of events, this behavior is repeated. This mode is called leading edge (at the beginning).

Leading edge debounce

You can pass an optional third argument to the Lodash library's debounce method, a parameter object that has two properties: leading (default false) and trailing (default true). These settings change the mode and specify whether the function should be triggered at the beginning of the event stream or at the end, after a pause.

document.addEventListener(
"scroll",
_.debounce(
() => {
console.log("Scroll handler call on every event stream start");
},
300,
{
leading: true,
trailing: false,
}
)
);

In practice, the leading mode can be used, for example, when you need to execute the function of sending a request to the server at the first click of a button, and then ignore all subsequent clicks until paused. The example shows debounce in both modes for the scroll event.