Debouncing & Throttling

📖 Concept

Debouncing and Throttling are rate-limiting techniques that control how often a function is called.

Debounce — Waits until the user STOPS triggering for N ms, then calls once. Use for: search input, window resize, form validation.

Throttle — Calls at most once every N ms, no matter how often triggered. Use for: scroll events, mouse move, game loops.

🏠 Real-world analogy: Debounce is like an elevator — it waits until people stop pressing buttons, then moves. Throttle is like a turnstile — it lets one person through every few seconds, no matter how many are waiting.

💻 Code Example

codeTap to expand ⛶
1// Debounce implementation
2function debounce(fn, delay, { leading = false } = {}) {
3 let timer;
4 let isLeading = leading;
5 return function(...args) {
6 if (isLeading && !timer) {
7 fn.apply(this, args);
8 isLeading = false;
9 }
10 clearTimeout(timer);
11 timer = setTimeout(() => {
12 if (!leading) fn.apply(this, args);
13 timer = null;
14 isLeading = leading;
15 }, delay);
16 };
17}
18
19// Throttle implementation
20function throttle(fn, limit) {
21 let inThrottle = false;
22 let lastArgs = null;
23 let lastThis = null;
24 return function(...args) {
25 if (!inThrottle) {
26 fn.apply(this, args);
27 inThrottle = true;
28 setTimeout(() => {
29 inThrottle = false;
30 if (lastArgs) {
31 fn.apply(lastThis, lastArgs);
32 lastArgs = null;
33 lastThis = null;
34 }
35 }, limit);
36 } else {
37 lastArgs = args;
38 lastThis = this;
39 }
40 };
41}
42
43// Usage examples
44const searchInput = document.querySelector("#search");
45const handleSearch = debounce((query) => {
46 console.log("Searching:", query);
47 // fetch(`/api/search?q=${query}`)
48}, 300);
49searchInput.addEventListener("input", (e) => handleSearch(e.target.value));
50
51const handleScroll = throttle(() => {
52 console.log("Scroll position:", window.scrollY);
53}, 200);
54window.addEventListener("scroll", handleScroll);
55
56// requestAnimationFrame throttle (60fps)
57function rafThrottle(fn) {
58 let ticking = false;
59 return function(...args) {
60 if (!ticking) {
61 requestAnimationFrame(() => {
62 fn.apply(this, args);
63 ticking = false;
64 });
65 ticking = true;
66 }
67 };
68}

🏋️ Practice Exercise

Mini Exercise:

  1. Implement a search bar with debounced API calls
  2. Build a scroll position indicator with throttled updates
  3. Create a "Save draft" feature that debounces saving to localStorage
  4. Implement a window resize handler with throttling

⚠️ Common Mistakes

  • Confusing debounce and throttle — debounce waits for inactivity, throttle limits frequency

  • Creating new debounced/throttled functions on every render — memoize or define outside the render

  • Not preserving this context — use .apply(this, args) inside the wrapper

  • Forgetting to cancel debounce/throttle on component unmount — leads to memory leaks or errors

  • Setting delay too long (missed updates) or too short (not effective) — benchmark for your use case

💼 Interview Questions

🎤 Mock Interview

Mock interview is powered by AI for Debouncing & Throttling. Login to unlock this feature.