Understanding Debouncing and Throttling in JavaScript: A Detailed Guide

In JavaScript, handling events like scrolling, resizing, or typing can sometimes lead to performance issues if functions are called too frequently. To address this, two powerful techniques—debouncing and throttling—are commonly used to control how often a function executes. In this blog, we'll explore what these techniques are, how they differ, and how to implement them using practical examples. We'll also discuss their real-world applications to help you decide when to use each one.
Let’s dive in!
What Are Debouncing and Throttling?
Before we look at code, let’s define these terms clearly:
Debouncing: This technique delays the execution of a function until a certain period of inactivity has passed. If the event (e.g., typing) is triggered again before the delay ends, the timer resets. The function only runs when the events stop for long enough.
Throttling: This technique limits how often a function can execute over a specified time interval. It ensures the function runs at most once within that interval, no matter how many times the event is triggered.
Think of debouncing as waiting for calm after a storm, and throttling as setting a steady rhythm regardless of how chaotic things get.
Example 1: Debouncing in Action
Let’s start with a debouncing implementation. Here’s the code we’ll analyze:
function ptaNahi(fn, delay) {
let myId;
return function (...args) {
clearTimeout(myId);
myId = setTimeout(() => {
fn.apply(this, args);
}, delay * 1000);
};
}
const sachMePatanahi = ptaNahi(() => console.log("I am done"), 2);
sachMePatanahi();
sachMePatanahi();
sachMePatanahi();
sachMePatanahi();
sachMePatanahi();
sachMePatanahi();
How It Works
Function Definition: ptaNahi takes two parameters:
fn: The function to debounce (in this case, a function that logs "I am done").
delay: The time to wait (in seconds) before executing fn.
Closure and Timer: It returns a new function that:
Clears any existing timeout using clearTimeout(myId) to reset the timer.
Sets a new timeout with setTimeout to call fn after delay * 1000 milliseconds (converting seconds to milliseconds).
Behavior: When sachMePatanahi is called multiple times in quick succession:
Each call resets the timer.
The function fn only executes once, 2 seconds after the last call, assuming no further calls interrupt the timer.
Output
If you run this code and call sachMePatanahi() six times within, say, 1 second, you’ll see:
Nothing happens immediately.
After a 2-second pause following the last call, "I am done" is logged to the console once.
This is debouncing at work—it waits for a break in the action before proceeding.
Example 2: Throttling in Action
Now, let’s examine a throttling implementation:
function ptaNahi(fn, delay) {
let myId = null;
return function (...args) {
if (myId === null) {
fn.apply(this, args);
myId = setTimeout(() => {
myId = null;
}, 1000 * delay);
}
};
}
const sachmePatanahi = ptaNahi(
() => console.log("Hi first it runs then it will wait"),
10
);
sachmePatanahi();
sachmePatanahi();
sachmePatanahi();
sachmePatanahi();
sachmePatanahi();
sachmePatanahi();
sachmePatanahi();
sachmePatanahi();
How It Works
Function Definition: ptaNahi takes the same parameters:
fn: The function to throttle (logs "Hi first it runs then it will wait").
delay: The minimum time interval (in seconds) between executions.
Closure and Flag: It returns a new function that:
Checks if myId is null. If it is, the function can run.
Executes fn immediately and sets a timeout to reset myId to null after delay * 1000 milliseconds.
If myId is not null (i.e., the timeout is still active), it skips the execution.
Behavior: When sachmePatanahi is called multiple times:
The first call runs fn immediately and starts a 10-second timer.
Any calls within the next 10 seconds are ignored.
After 10 seconds, myId resets to null, and the next call can trigger fn again.
Output
If you call sachmePatanahi() eight times in quick succession:
"Hi first it runs then it will wait" is logged once immediately.
No further logs occur for 10 seconds, even if you keep calling it.
After 10 seconds, the next call will log the message again.
This is throttling—it ensures a controlled pace.
Key Differences Between Debouncing and Throttling
| Aspect | Debouncing | Throttling |
| Execution Timing | Runs after a pause in events. | Runs at most once per time interval. |
| Behavior | Resets the timer on each event. | Ignores events during the cooldown. |
| Use Case | Waits for the user to "finish" an action. | Limits rate during continuous action. |
| Example Output | One call after 2s of silence. | One call every 10s, starting immediately. |
Real-World Use Cases
Debouncing
Search Input: Imagine a search bar fetching results from an API. Debouncing ensures the request is sent only after the user stops typing for, say, 500ms, reducing unnecessary server calls.Form Validation: Validate input only after the user pauses, avoiding checks on every keystroke.
Throttling
Scroll Events: Update a sticky header’s position every 100ms while scrolling, instead of on every pixel change.Window Resizing: Adjust layouts at a fixed interval during resizing, preventing performance lag.Throttling a Submit Button: Once a user clicks on the submit button to check an answer, then it can submit again after 20 seconds.
Why Use These Techniques?
Without debouncing or throttling, rapid events can overwhelm your application:
Performance: Too many function calls bog down the browser.
User Experience: Unnecessary updates or API calls can frustrate users or waste resources.
By controlling execution, you optimize both efficiency and responsiveness.
Using Libraries
While our examples work well for learning, production code often benefits from battle-tested libraries like throttle-debounce:
These handle edge cases (e.g., canceling timeouts, leading/trailing options) that you might not want to reinvent.
Conclusion
Debouncing and throttling are essential tools in a JavaScript developer’s toolkit. They help manage event-driven code efficiently, ensuring your applications remain performant and user-friendly. The examples we explored—ptaNahi for debouncing and throttling—demonstrate the core concepts simply and effectively.
Use debouncing when you need to wait for a pause, like in search inputs or form submissions.
Use throttling when you need a steady rhythm, like in scroll or resize handlers.
Next time you’re dealing with rapid-fire events, reach for one of these techniques—you’ll thank yourself (and so will your users)! Happy coding!



