π§ Understanding Debounce and Throttle in JavaScript (Made Super Simple!)

When building modern web apps, performance matters β a lot. If you're handling events like scroll
, resize
, or input
, you might accidentally run the same function hundreds of times in a second! Thatβs where debounce and throttle come in.
Letβs break these two down step by step, using real code and even a pizza shop analogy π to help it all make sense.
π‘ Simple Definitions
Debounce:
Debounce waits for a pause β it runs your function after the event has stopped firing for a certain amount of time.
Throttle:
Throttle limits how often a function can run β it ensures the function runs at most once every N milliseconds, no matter how many times the event happens.
Confused ? Letβs try to understand via an example !
π¦ Code Examples (How They Work)
β Debounce Example:
window.addEventListener('resize', debounce(() => {
console.log('Resize event handler called!');
}, 300));
π Output:
When you resize the window, this only logs once β after you stop resizing for 300ms. It wonβt spam the console while you're resizing.
β Throttle Example:
window.addEventListener('scroll', throttle(() => {
console.log('Scroll event handler called!');
}, 200));
π Output:
Even if you scroll like crazy, this logs the message at most once every 200ms. It keeps things smooth and avoids performance bottlenecks.
Still confused ? Letβs try to understand via an exciting analogy !
π Real-Life Analogy: The Pizza Ordering Receptionist
Letβs imagine a pizza shop with a very busy receptionist. Sheβs trying to manage customer calls.
Debounce:
The receptionist waits until calls stop coming in for 5 minutes. Only then, she processes the last caller's order. If a new call comes in during those 5 minutes, she resets the timer and waits again.
π... (wait)... π... (wait again)... silence... β Now take the last order.
Great when: You want to wait for the user to finish their input (like typing a search term) before doing something.
Throttle:
The receptionist picks up only one call every 5 minutes, no matter how many people call. She tells everyone else to wait. Even if 10 people call, she only takes 1 order every 5 minutes.
π β Order taken. β³ Waiting... πππ β (Ignored)... π β Next order.
Great when: You want regular updates (like scroll or mouse move) without overloading the system.
π Debounce vs Throttle (Quick Comparison)
Feature | Debounce | Throttle |
Function Runs | After a delay of no activity | At most once every fixed interval |
Common Use Case | Typing in search bars, resizing windows | Scrolling, mouse movement, window resizing (for animation) |
Behavior | Delays function until user stops doing something | Allows function to run at intervals during activity |
Visual | π Wait until calm, then act | π¦ Act at green light intervals only |
π§βπ» Write Your Own Debounce and Throttle in JavaScript
Let's now build our own versions of debounce and throttle β this helps you understand how they work under the hood.
π οΈ Debounce: Our Own Version
function debounce(func, delay) {
let timerId;
return function (...args) {
const context = this;
clearTimeout(timerId);
timerId = setTimeout(() => {
func.apply(context, args);
}, delay);
};
}
β How it works:
timerId
stores the reference to the timeout.Every time the function is called, we clear the previous timer.
We wait
delay
milliseconds since the last call, then execute the function.
π οΈ Throttle: Your Own Version
function throttle(func, limit) {
let lastCalled = 0;
return function (...args) {
const context = this;
const now = Date.now();
if (now - lastCalled >= limit) {
lastCalled = now;
func.apply(context, args);
}
};
}
β How it works:
We store the time when the function was last called.
Each time the event fires, we check if enough time has passed.
If yes, we run the function and update
lastCalled
.
π€ Whatβs ...args
and context
?
...args
This collects all arguments passed to your throttled or debounced function so you can forward them to the real function later.
debouncedSearch("hello", "user");
...args
becomes: ["hello", "user"]
context
(this
)
Sometimes, your function might depend on the object it belongs to (like a method on an object). If we donβt preserve this
, we can lose context.
Thatβs why we do:
const context = this;
func.apply(context, args);
This ensures the original function is called in the correct context with the right arguments.
π― Final Thoughts
Debounce and throttle are small tools that solve big performance problems. Whether youβre building a live search, lazy-loading images, or optimizing a scroll-heavy UI β these two patterns are your best friends.
Subscribe to my newsletter
Read articles from Yash Grover directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
