Although similar, debouncing and throttling serve different purposes in JavaScript. Let’s explore together their differences and similarities.
I have always found the difference between debouncing and throttling in JavaScript tricky.
They both help solve similar issues, such as mitigate performance issues because of excessive function calls, but they serve different purposes.
And they work well in different scenarios.
In this article, I want to briefly talk about what they are, and how they can help us reduce clutter and improve performance.
What is debouncing?
Debouncing ensures a function executes only after a specific period of inactivity following the last event trigger.
In simpler words, it’s a technique that stops a function from being called repeatedly in quick succession.
Let’s imagine a practical use case.
We built a simple form interface with a search input field for our recipes blog. When the user types a character, we provide relevant recipe suggestions.
However, we don’t want our website to trigger a search every time the user types a character as this would generate too many requests and impact our blog’s performance, too.
That’s where debouncing comes into play. We first wait until the user stopped typing, and then we execute our function.
We can achieve this by specifying a duration in which we “freeze” every API request until the action of typing is over:
function debounce(func, delay) {
let timer;
return function(...args) {
clearTimeout(timer);
timer = setTimeout(() => func.apply(this, args), delay);
};
}
const searchInput = document.getElementById("search");
const fetchResults = debounce(() => console.log("Fetching search results..."), 300);
searchInput.addEventListener("input", fetchResults);
In this example, we wait 300 milliseconds after the user stops typing to run fetchResults()
and actually display the results.
I can think of many scenarios where debouncing is useful.
Handling quick events: When we deal with events that can occur in a short time, such as user inputs or button clicks.
Optimizing costly operations: When we want to run expensive calculations only after an action has finished, like when the browser’s window stops resizing.
Managing user interactions: When we want to focus on one user interaction at the time, pausing all other interactions on our website or app until the first one is complete.
In this CodePen, you can see a simple debounce function in action. The function waits 500 milliseconds after the user stops typing. Then, it makes a request to the JSONPlaceholder API to display the relevant results.
What is throttling?
According to the MDN docs, throttling in programming refers to:
slowing down a process such that an operation can only be performed at a certain rate.
What does “at a certain rate” mean in this context?
In computing and networking there is a concept called rate limit. It’s a way to manage how many actions can happen in a set period of time. It’s crucial in certain scenarios as it prevents system overload.
If I had to think of an analogy, I would compare it to a water tap. We can set a rate limit to control the flow of water coming from the tap to avoid overflowing the sink.
The way this control works is the key difference between debouncing and throttling.
Debouncing: Delays a function execution until another activity stops for a certain period of time.
Throttling: Limits how often a function runs, ensuring that it’s executed at least once, but at given intervals.
function throttle(func, interval) {
let lastTime = 0;
return function(...args) {
const now = Date.now();
if (now - lastTime >= interval) {
func.apply(this, args);
lastTime = now;
}
};
}
const handleScroll = throttle(() => console.log("User scrolled!"), 500);
window.addEventListener("scroll", handleScroll);
In this snippet, we use **throttling **to control how often the “User scrolled!” message is displayed. Even if the user scrolls quickly, we only display the message at most once every 500 milliseconds.
If you want to test out throttling in a real-world scenario, consider the following situations:
Handling frequent user events: If you need to handle user-related events like scrolling, resizing or typing that can potentially trigger multiple times. Throttling can avoid excessive updates, which also translates in a smoother and more responsive user experience as it can reduce latency.
Limiting API calls: If you want to limit the number of API requests a user can make in a certain time. This is particularly useful if we want to make sure that we stay within API quotas.
Check out this CodePen for a quick example of how throttling works. Whenever the users scroll the page, we display a “Loading more content…” message on the page. Without throttling, each scroll event would trigger the message. However with throttling in place, the message is logged at set intervals. This gives us more control and reduces the jank.
Bonus analogy
I like to use real-life analogies to explain tricky concepts using simple words.
Let’s use a photography analogy to summarize the difference between debouncing and throttling.
Somebody gifted us a camera for Christmas. We want to use it to take the perfect shot of a seagull diving into the water to capture a fish. But we are not interested in taking many shots of the seagull as it flies down. Instead, we want to wait until it captured the fish and holds still before snapping the photo. This is debouncing.
Some time later, we decide to explore a different approach. We want to take a time-lapse of the seagull launching into the water to capture its prey. So we set our camera to take a photo every 1 second. In this way, we can record the action at steady intervals, no matter how fast the seagull moves. This is throttling.
If you found this helpful, please let me know in the comments!