Counting Semaphore For Async Concurrency
A counting semaphore that bounds in-flight async tasks with FIFO fairness and a safe release path for pooled resources.
Code
export class Semaphore {
constructor(max) {
if (!Number.isInteger(max) || max < 1) throw new RangeError("max must be a positive integer");
this.max = max;
this.active = 0;
this.waiters = [];
}
get inFlight() {
return this.active;
}
async acquire() {
if (this.active < this.max) {
this.active += 1;
return this.makeRelease();
}
await new Promise((resolve) => this.waiters.push(resolve));
return this.makeRelease();
}
makeRelease() {
let released = false;
return () => {
if (released) return;
released = true;
this.active -= 1;
const next = this.waiters.shift();
if (next) {
this.active += 1;
next();
}
};
}
async run(task) {
const release = await this.acquire();
try {
return await task();
} finally {
release();
}
}
async runAll(tasks) {
return Promise.all(tasks.map((t) => this.run(t)));
}
}Report a problem with this exampleOpens a pre-filled issue on GitHub.