index.js
function stopcock(fn, options) {
  options = Object.assign(
    {
      queueSize: Math.pow(2, 32) - 1,
      bucketSize: 40,
      interval: 1000,
      limit: 2
    },
    options
  );

  const bucket = new TokenBucket(options);
  const queue = [];
  let timer = null;

  function shift() {
    clearTimeout(timer);
    while (queue.length) {
      const delay = bucket.consume();

      if (delay > 0) {
        timer = setTimeout(shift, delay);
        break;
      }

      const data = queue.shift();
      data[2](fn.apply(data[0], data[1]));
    }
  }

  function limiter() {
    const args = arguments;

    return new Promise((resolve, reject) => {
      if (queue.length === options.queueSize) {
        return reject(new Error('Queue is full'));
      }

      queue.push([this, args, resolve]);
      shift();
    });
  }

  Object.defineProperty(limiter, 'size', { get: () => queue.length });

  return limiter;
}
function stopcock(fn, options) {
  options = Object.assign(
    {
      queueSize: Math.pow(2, 32) - 1,
      bucketSize: 40,
      interval: 1000,
      limit: 2
    },
    options
  );

  const bucket = new TokenBucket(options);
  const queue = [];
  let timer = null;

  function shift() {
    clearTimeout(timer);
    while (queue.length) {
      const delay = bucket.consume();

      if (delay > 0) {
        timer = setTimeout(shift, delay);
        break;
      }

      const data = queue.shift();
      data[2](fn.apply(data[0], data[1]));
    }
  }

  function limiter() {
    const args = arguments;

    return new Promise((resolve, reject) => {
      if (queue.length === options.queueSize) {
        return reject(new Error('Queue is full'));
      }

      queue.push([this, args, resolve]);
      shift();
    });
  }

  Object.defineProperty(limiter, 'size', { get: () => queue.length });

  return limiter;
}
Limit the execution rate of a function using a leaky bucket algorithm.

@param {Function} fn The function to rate limit calls to
@param {Object} options Options object
@param {Number} options.limit The number of allowed calls per `interval`
@param {Number} options.interval The timespan where `limit` is calculated
@param {Number} options.queueSize The maximum size of the queue
@param {Number} options.bucketSize The capacity of the bucket
@return {Function}
@public