Rate limit to N calls per window
Client-side rate limiting keeps you inside an API's quota and stops a runaway effect from firing a hundred requests. The subtlety is that the window rolls: the limit is on any windowMs stretch ending now, not on fixed buckets. A naive counter reset every windowMs lets through twice the limit across a bucket boundary.
Implement rateLimit(fn, limit, windowMs). It returns a wrapper. On each call, count the allowed invocations that happened within the last windowMs milliseconds; if that count is below limit, invoke fn with the wrapper's arguments and its this, record the time of the invocation, and return fn's result. Otherwise drop the call — fn is not invoked — and return undefined. Invocations older than windowMs no longer count towards the limit, so a call becomes possible again as soon as the oldest recorded invocation ages out. A limit of 0 means fn is never invoked.
Arguments
fnFunction- The function to rate-limit.
limitnumber- Maximum number of allowed invocations in any
windowMsstretch. windowMsnumber- Width of the rolling window, in milliseconds.
Returns
Function — A wrapper that invokes fn up to limit times per rolling windowMs and drops the rest.
Examples
let calls = 0;
const run = rateLimit(() => ++calls, 3, 1000);
run(); run(); run(); // 1, 2, 3
run(); // undefined — over the limit this window
// 1s later, oldest invocation ages out — next call fires againThe window rolls: a slot opens up as soon as the oldest recorded invocation turns windowMs old.
const never = rateLimit(() => "x", 0, 1000);
never(); never(); // both undefined, fn never invokedWhat it has to do
- Allow up to
limitinvocations in anywindowMsstretch. - Drop calls beyond the limit without invoking
fn, returningundefined. - Use a rolling window: an invocation stops counting once it is older than
windowMs. - Forward arguments and preserve
thisfor allowed calls, returningfn's result. - Never invoke
fnwhenlimitis0.
Notes
- A rolling window and a fixed bucket are not the same thing. A counter that resets every
windowMslets2 * limitcalls through across a bucket boundary. - Keep an array of timestamps of allowed invocations. On each call, filter out the ones older than
windowMsfirst, then compare the remaining length againstlimit.
Stuck? The javascript course covers everything this challenge needs.
- 1.allows up to the limit and drops the rest
- 2.allows more calls once the window has passed
- 3.the window rolls rather than resetting in buckets
- 4.forwards arguments and preserves this on allowed calls
- 5.a limit of zero never invokes the function
These assertions run in your browser the moment you hit Run. Pass all of them to claim the XP.
Discussion
Sign in to postNo comments yet. Be the first to say something.