Throttle Polyfill
UtilitiesPolyfill
Implement a throttle(fn, limit) function.
Function Signature:
function throttle(fn, limit) { }
Requirements:
- Return a new function that executes
fnat most once perlimitms - Leading-edge: fire immediately on the first call, then block for
limitms - Preserve
thiscontext and all arguments
Bonus:
- Implement the trailing-call variant using timestamps so the final blocked call also executes
Examples
Example 1
Input
const throttled = throttle(() => console.log('tick'), 100);
throttled(); throttled(); throttled();
// all three fired within 50msOutput
tickExplanation
Only the first call executes immediately. The next two are blocked within the 100ms window.
Notes
- Debounce waits for silence. Throttle fires on a fixed cadence. Be ready to state that difference in one sentence.
Hints
Editorial: Throttle Polyfill
Implementing throttle from scratch
Throttle guarantees a function runs at most once per interval, no matter how often it is called. Use case: scroll or resize handlers where you want regular updates, not silence-triggered ones.
Leading-edge implementation (flag-based)
function throttle(fn, limit) { let inThrottle = false; return function (...args) { const context = this; if (!inThrottle) { fn.apply(context, args); inThrottle = true; setTimeout(() => (inThrottle = false), limit); } }; }
This fires immediately on the first call, then ignores all calls for limit ms. Simple and correct for most use cases.
With trailing call (timestamp-based)
The flag-based approach silently drops the final call if it lands inside the blocked window. If that matters, use the timestamp variant — it schedules the blocked call to run at the end of the interval:
function throttle(fn, limit) { let lastRan = 0; let timer; return function (...args) { const context = this; const now = Date.now(); if (now - lastRan >= limit) { fn.apply(context, args); lastRan = now; } else { clearTimeout(timer); timer = setTimeout(() => { fn.apply(context, args); lastRan = Date.now(); }, limit - (now - lastRan)); } }; }
Debounce vs throttle — one-sentence difference
Debounce resets on every call and runs once activity stops.
Throttle runs on a fixed schedule during continuous activity.
When to use which
| Scenario | Use |
|---|---|
| Search input — fire after user pauses | debounce |
| Scroll handler — update every 100ms | throttle |
| Window resize — recalculate after resize ends | debounce |
| Rate-limit button clicks | throttle |
Edge cases to mention
- The flag-based version drops the last call in a burst — mention whether that matters for the use case
- The timestamp version fires on both leading and trailing edges — two executions for a burst that spans one interval
- Always preserve
thiscontext with.apply(context, args)when the throttled function may be a method
</>JavaScript
Loading editor…
Test Result
Run your code, or Submit to test it