All files / src/lib/helpers promiseLimit.ts

100% Statements 25/25
100% Branches 4/4
100% Functions 6/6
100% Lines 25/25

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60            40x 40x 40x       67x 67x 61x 61x   6x           67x 67x 6x   61x         5x       40x 40x   40x       67x 67x 67x 62x   67x       40x 40x   36x     5x  
class Semaphore {
  private maxConcurrency: number;
  private currentConcurrency: number;
  private queue: (() => void)[];
 
  constructor(maxConcurrency: number) {
    this.maxConcurrency = maxConcurrency;
    this.currentConcurrency = 0;
    this.queue = [];
  }
 
  async acquire() {
    return new Promise<void>((resolve) => {
      if (this.currentConcurrency < this.maxConcurrency) {
        this.currentConcurrency++;
        resolve();
      } else {
        this.queue.push(resolve);
      }
    });
  }
 
  release() {
    const resolve = this.queue.shift();
    if (resolve) {
      resolve();
    } else {
      this.currentConcurrency--;
    }
  }
}
 
const promiseLimit = async <T>(
  n: number,
  list: (() => Promise<T>)[]
): Promise<T[]> => {
  const semaphore = new Semaphore(n);
  const results: T[] = [];
 
  const limitedFn = async (
    fn: () => Promise<T>,
    index: number
  ): Promise<void> => {
    await semaphore.acquire();
    try {
      const result = await fn();
      results[index] = result;
    } finally {
      semaphore.release();
    }
  };
 
  const promises = list.map(limitedFn);
  await Promise.all(promises);
 
  return results;
};
 
export default promiseLimit;