There is nothing built-in for this, so you have to create your own. AFAIK, there is no library for this yet.
First, start with a “deferral" - a promise that allows the external code to resolve it:
class Deferral<T> { constructor() { this.promise = new Promise<T>((resolve, reject) => { this.resolve = resolve; this.reject = reject; }); } promise: Promise<T>; resolve: (thenableOrResult?: T | PromiseLike<T>) => void; reject: (error: any) => void; }
Then you can define a “wait queue” that represents all the blocks of code that are waiting to enter the critical section:
class WaitQueue<T> { private deferrals: Deferral<T>[]; constructor() { this.deferrals = []; } get isEmpty(): boolean { return this.deferrals.length === 0; } enqueue(): Promise<T> { const deferral = new Deferral<T>(); this.deferrals.push(deferral); return deferral.promise; } dequeue(result?: T) { const deferral = this.deferrals.shift(); deferral.resolve(result); } }
Finally, you can define an asynchronous semaphore, as such:
export class AsyncSemaphore { private queue: WaitQueue<void>; private _count: number; constructor(count: number = 0) { this.queue = new WaitQueue<void>(); this._count = count; } get count(): number { return this._count; } waitAsync(): Promise<void> { if (this._count !== 0) { --this._count; return Promise.resolve(); } return this.queue.enqueue(); } release(value: number = 1) { while (value !== 0 && !this.queue.isEmpty) { this.queue.dequeue(); --value; } this._count += value; } }
Usage example:
async function performActionsInParallel() { const semaphore = new AsyncSemaphore(10); const listOfActions = [...]; const promises = listOfActions.map(async (action) => { await semaphore.waitAsync(); try { await doSomething(action); } finally { semaphore.release(); } }); const results = await Promise.all(promises); }
This method first creates a choke and then immediately starts all asynchronous operations. Each asynchronous operation first (asynchronously) waits for the semaphore to be released, then performs the action, and finally frees the semaphore (allows another). When all asynchronous operations are completed, all results will be obtained.
Warning: this code is not 100% fully tested. I have not even tried this once.
source share