Implement throttle(fn, limit)
Implement throttle(fn, limit) that returns a throttled wrapper: fn runs at most once per limit ms no matter how often the wrapper is called. The first call runs immediately (leading edge); calls within the window are ignored. Preserve this and forward all arguments to fn.
function throttle(fn, limit) {
// your code here
}
Write the implementation.
Track lastRun (timestamp) in the closure, starting so the first call passes. On each call compute now = Date.now(); if now - lastRun >= limit, set lastRun = now and run fn.apply(this, args), otherwise ignore the call. This caps fn to one run per limit window on the leading edge while preserving this and arguments.
- ✗Confusing throttle with debounce — throttle caps the rate, debounce waits for quiet
- ✗Initializing
lastRunso the very first call is wrongly skipped - ✗Losing
this/arguments by callingfn()directly instead offn.apply(this, args)
- →How would you add a trailing call so the final invocation is not lost?
- →Why does the leading-edge version fire the first call immediately?
Solution
Track the timestamp of the last run; execute fn only if the limit window has elapsed.
function throttle(fn, limit) {
let lastRun = -Infinity;
return function (...args) {
const now = Date.now();
if (now - lastRun >= limit) {
lastRun = now;
fn.apply(this, args);
}
};
}
How it works
lastRun holds the time of the last actual fn run and lives in the closure across calls. The initial value -Infinity guarantees the very first call passes the check immediately (the leading edge).
On each call we compare now - lastRun against limit. If enough time has passed, we update lastRun and run fn.apply(this, args), preserving the context and arguments. Otherwise the call is simply ignored. This caps fn to at most one run per limit ms no matter how often the wrapper is invoked. </content>