Skip to content

Instantly share code, notes, and snippets.

@randName
Last active February 4, 2021 04:19
Show Gist options
  • Save randName/e2b69bf4f6a20171f647237767875578 to your computer and use it in GitHub Desktop.
Save randName/e2b69bf4f6a20171f647237767875578 to your computer and use it in GitHub Desktop.
yet another rate limiting wrapper

Yet Another Rate-limiting Wrapper

rateLimit(fn[, options])

  • fn <Function> Function that will be rate-limited
  • options <Object> Configurable options
    • max <number> Maximum number of active instances. Default: 10
    • delay <number> Minimum delay between calls in milliseconds. Default: 10
  • Returns: <Function> with the same signature as fn

Example

import { rateLimit } from './rateLimit.js'

const ratedFetch = rateLimit(fetch)

// use .allSettled so that errors don't stop everything
Promise.allSettled([/* URLs to fetch */].map((url) => ratedFetch(url).then((r) => {
  // process response as usual (e.g. `r.json()`)
})).then((results) => console.log('done', results))
export default function rateLimit (fn, opts = {}) {
// delay - minimum milliseconds between calls
// max - maximum number of running instances
const { delay = 10, max = 10 } = opts
let last = 0
let running = 0
const queue = []
return async (...args) => {
const wait = delay + last - Date.now()
if (wait > 0) await new Promise((r) => setTimeout(r, wait))
if (running >= max) await new Promise((r) => queue.push(r))
++running
last = Date.now()
try {
return await fn(...args)
} catch (err) {
throw err
} finally {
--running
queue.length && queue.shift()()
}
}
}
export default function rateLimit(t,e={}){const a=[],{delay:n=10,max:o=10}=e;let i=0,r=0;return async(...e)=>{const s=n+i-Date.now();s>0&&await new Promise((t=>setTimeout(t,s))),r>=o&&await new Promise((t=>a.push(t))),++r,i=Date.now();try{return await t(...e)}catch(t){throw t}finally{--r,a.length&&a.shift()()}}}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment