blob: a2b5206f674fc5ff035ed941715b094bc0465bf2 [file]
// Copyright 2026 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
export class Semaphore {
readonly #max: number;
#count = 0;
readonly #queue: Array<() => void> = [];
constructor(max: number) {
this.#max = max;
}
async acquire(): Promise<void> {
if (this.#count < this.#max) {
this.#count++;
return await Promise.resolve();
}
return await new Promise(resolve => {
this.#queue.push(resolve);
});
}
release(): void {
if (this.#queue.length > 0) {
const next = this.#queue.shift();
next?.();
} else {
this.#count--;
}
}
}
export async function withConcurrencyLimit<T>(
tasks: Array<() => Promise<T>>,
limit: number,
): Promise<T[]> {
const semaphore = new Semaphore(limit);
return await Promise.all(
tasks.map(async task => {
await semaphore.acquire();
try {
return await task();
} finally {
semaphore.release();
}
}),
);
}