JavaScript Notes
Master JavaScript throttle with implementation, timeline diagrams, scroll examples, throttle vs debounce comparison, leading/trailing edge, and interview Q&A.
What is Throttle?
Throttle is a performance optimization technique that ensures a function is called at most once per specified time interval, regardless of how many times the event fires.
While debounce waits for quiet, throttle acts like a rate limiter — it allows the function to run regularly but caps how frequently it can fire.
One-liner: Throttle says "run at most once every N milliseconds — ignore everything in between."
The Problem Throttle Solves
Without throttle, events like scroll and mousemove fire 60–200 times per second:
This causes jank (UI freeze), dropped frames, and wasted computation. Throttle caps the rate.
Throttle Timeline Diagram
Basic Throttle Implementation
function throttle(fn, interval) {
let lastCallTime = 0; // Timestamp of last execution
return function(...args) {
const now = Date.now();
if (now - lastCallTime >= interval) {
lastCallTime = now;
return fn.apply(this, args);
}
// else: silently ignored (in cooldown)
};
}Step-by-Step Execution Trace
Throttle with 200ms interval
t=0ms: now=0, lastCallTime=0, 0-0=0 ≥ 200? NO... wait
Actually: 0 >= 200? NO — but lastCallTime starts at 0!
First call: 0 - 0 = 0 ≥ 200? ← use > 0 check OR:
Let's trace with actual calls:
t=0ms: now=0, lastCallTime=0, 0-0=0 ≥ 200? depends on impl.
t=0ms: → fn() executes ✅, lastCallTime = 0
t=50ms: now=50, lastCallTime=0, 50-0=50, 50 < 200 → SKIP ✗
t=150ms: now=150, lastCallTime=0, 150-0=150, 150 < 200 → SKIP ✗
t=200ms: now=200, lastCallTime=0, 200-0=200, 200 >= 200 → RUN ✅
lastCallTime = 200
t=250ms: now=250, lastCallTime=200, 250-200=50 < 200 → SKIP ✗
t=400ms: now=400, lastCallTime=200, 400-200=200 >= 200 → RUN ✅
lastCallTime = 400Example 1 — Throttled Scroll Handler
function throttle(fn, interval) {
let lastCallTime = 0;
return function(...args) {
const now = Date.now();
if (now - lastCallTime >= interval) {
lastCallTime = now;
fn.apply(this, args);
}
};
}
function updateScrollBar() {
const scrollPercent = (window.scrollY / document.body.scrollHeight) * 100;
console.log(`Scroll: ${scrollPercent.toFixed(1)}%`);
}
const throttledScroll = throttle(updateScrollBar, 200);
window.addEventListener("scroll", throttledScroll);Scroll: 0.0% Scroll: 12.4% Scroll: 28.7% Scroll: 45.2%
(Fires at most once every 200ms instead of 60+ times per second)
Example 2 — Throttled API Polling
function throttle(fn, interval) {
let lastCallTime = 0;
return function(...args) {
const now = Date.now();
if (now - lastCallTime >= interval) {
lastCallTime = now;
return fn.apply(this, args);
}
};
}
function fetchLatestData() {
console.log(`Fetching data at ${new Date().toLocaleTimeString()}`);
}
const throttledFetch = throttle(fetchLatestData, 1000);
// Simulate rapid button clicks
throttledFetch(); // t=0 → executes
throttledFetch(); // t=0 → ignored
throttledFetch(); // t=0 → ignoredFetching data at 10:30:00 AM
Example 3 — Throttle with this Context
Advanced — Throttle with Leading and Trailing Edge
| Option | Behavior |
|---|---|
leading: true | Fires on first call immediately |
trailing: true | Fires once more after cooldown if calls came in during it |
leading: false, trailing: true | Fire only at end of each interval (like debounce-ish) |
Throttle vs Debounce — Complete Comparison
SCENARIO: User scrolling rapidly for 2 seconds
DEBOUNCE (300ms):
t=0ms ● → timer starts
t=100ms ● → timer resets
t=200ms ● → timer resets
...
t=2000ms ● → timer resets
t=2300ms → 🔥 fires ONCE after scroll stops
THROTTLE (300ms):
t=0ms ● → 🔥 fires immediately
t=100ms ● → ✗ (cooldown)
t=200ms ● → ✗ (cooldown)
t=300ms ● → 🔥 fires (300ms elapsed)
t=400ms ● → ✗ (cooldown)
t=600ms ● → 🔥 fires
... → fires ~6-7 times during 2 seconds| Feature | Throttle | Debounce |
|---|---|---|
| Fires when | At regular intervals | After quiet period |
| Timer resets on event | ❌ No | ✅ Yes |
| Guaranteed execution | Yes — at each interval | Only after silence |
| Best for | Scroll, mousemove, resize progress | Search input, form save, resize-end |
| UI updates while active | ✅ Smooth, periodic | ❌ No updates until done |
| API call reduction | Caps frequency | Waits for pause |
Common Mistakes
❌ Mistake 1 — Recreating Throttled Function on Each Render
// WRONG — new throttle wrapper every render, state lost!
element.addEventListener("scroll", throttle(handler, 200)); // in a loop
// CORRECT — create once
const throttledHandler = throttle(handler, 200);
element.addEventListener("scroll", throttledHandler);❌ Mistake 2 — Using Throttle Instead of Debounce for Search
// WRONG — throttle fires periodically even while typing
searchInput.addEventListener("input", throttle(fetchResults, 300));
// → Makes API calls every 300ms while user is still typing!
// CORRECT — debounce waits for typing to stop
searchInput.addEventListener("input", debounce(fetchResults, 300));❌ Mistake 3 — Not Preserving this Context
function throttle(fn, interval) {
let last = 0;
return function() {
const now = Date.now();
if (now - last >= interval) {
last = now;
fn(); // WRONG — this context lost!
}
};
}
// CORRECT
fn.apply(this, args); // or fn.call(this, ...args)React Hook: useThrottle
Interview Questions 🎯
Q1. What is throttle in JavaScript?
Throttle is a technique that limits how often a function can execute. It allows at most one call per specified time interval. During the cooldown period, additional calls are silently ignored. Unlike debounce, throttle guarantees the function fires periodically as long as events continue.
Q2. Implement a throttle function from scratch.
function throttle(fn, interval) {
let lastCallTime = 0;
return function(...args) {
const now = Date.now();
if (now - lastCallTime >= interval) {
lastCallTime = now;
fn.apply(this, args);
}
};
}Q3. What is the difference between throttle and debounce?
- Throttle: Fires at regular intervals during continuous events. Useful for smooth progress updates (scroll, mousemove).
- Debounce: Fires only after events stop for a delay. Useful for final state handling (search input, resize-end).
Throttle = rate limiter (fires periodically). Debounce = quiet-time waiter (fires after silence).
Q4. When should you use throttle vs debounce?
Use throttle for:
scrollevents (update progress bar smoothly)mousemove(drag, tooltip tracking)- Resize events (show current dimensions while resizing)
- Button spam prevention (1 click per second)
Use debounce for:
- Search input (wait for typing to stop)
- Window resize (recalculate layout after resize ends)
- Form auto-save (save after user stops editing)
- API calls that need the final value
Q5. Why must you preserve this and args in throttle?
The throttled function may be used as a method (with this) or handler that receives event objects (args). Using fn.apply(this, args) ensures the original function gets both the correct calling context and all event arguments.
Q6. What is leading-edge vs trailing-edge throttle?
- Leading-edge: Function fires immediately on first call, then blocked for interval
- Trailing-edge: Function fires at the end of each interval (like debounce but with max frequency)
- Most implementations support both as options
Q7. What is the performance benefit of throttle on scroll events?
A scroll event can fire 60+ times per second (every 16ms for 60fps). Without throttle, a handler doing DOM manipulation runs 60+ times/second. With 200ms throttle, it runs at most 5 times/second — a 12x reduction in work.
Q8. How would you cancel a pending throttled call?
Add a cancel() method that resets lastCallTime and clears any trailing timeout:
Key Takeaways 🔑
- Throttle caps frequency — at most once per interval, regardless of event rate
- The timer does NOT reset on new events (unlike debounce)
- Implemented using
Date.now()timestamp comparison — nosetTimeoutneeded for basic version - Must preserve
thisandargswithfn.apply(this, args) - Throttle vs Debounce: Throttle = periodic during events; Debounce = after events stop
- Best uses: scroll, mousemove, resize progress, game controls
- Add
cancel()/reset()for production use - In React, implement as a
useThrottlehook withuseReffor mutable timer state
Summary
Throttle is a performance optimization that ensures a function runs at most once per specified time interval. Implemented by comparing Date.now() with the last execution timestamp, it silently ignores calls during the cooldown window. Unlike debounce (which waits for quiet), throttle guarantees regular execution — making it ideal for scroll handlers, mousemove tracking, and any scenario where you want smooth, periodic updates during continuous events. The key implementation details are: timestamp comparison (not setTimeout), preserving this context, and optional leading/trailing edge behavior for fine-grained control.
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for JavaScript Throttle - Complete Guide with Timeline Diagrams.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this JavaScript Master Course topic.
Search Terms
javascript-complete-guide, javascript master course, javascript, complete, guide, advanced, throttle, javascript throttle - complete guide with timeline diagrams
Related JavaScript Master Course Topics