🧠 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:
timerIdstores the reference to the timeout.Every time the function is called, we clear the previous timer.
We wait
delaymilliseconds 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.



