UNPKG

es-toolkit

Version:

A state-of-the-art, high-performance JavaScript utility library with a small bundle size and strong type annotations.

101 lines (100 loc) 2.44 kB
//#region src/promise/semaphore.ts /** * A counting semaphore for async functions that manages available permits. * Semaphores are mainly used to limit the number of concurrent async tasks. * * Each `acquire` operation takes a permit or waits until one is available. * Each `release` operation adds a permit, potentially allowing a waiting task to proceed. * * The semaphore ensures fairness by maintaining a FIFO (First In, First Out) order for acquirers. * * @example * const sema = new Semaphore(2); * * async function task() { * await sema.acquire(); * try { * // This code can only be executed by two tasks at the same time * } finally { * sema.release(); * } * } * * task(); * task(); * task(); // This task will wait until one of the previous tasks releases the semaphore. */ var Semaphore = class { /** * The maximum number of concurrent operations allowed. * @type {number} */ capacity; /** * The number of available permits. * @type {number} */ available; deferredTasks = []; /** * Creates an instance of Semaphore. * @param capacity - The maximum number of concurrent operations allowed. * * @example * const sema = new Semaphore(3); // Allows up to 3 concurrent operations. */ constructor(capacity) { this.capacity = capacity; this.available = capacity; } /** * Acquires a semaphore, blocking if necessary until one is available. * @returns A promise that resolves when the semaphore is acquired. * * @example * const sema = new Semaphore(1); * * async function criticalSection() { * await sema.acquire(); * try { * // This code section cannot be executed simultaneously * } finally { * sema.release(); * } * } */ async acquire() { if (this.available > 0) { this.available--; return; } return new Promise((resolve) => { this.deferredTasks.push(resolve); }); } /** * Releases a semaphore, allowing one more operation to proceed. * * @example * const sema = new Semaphore(1); * * async function task() { * await sema.acquire(); * try { * // This code can only be executed by two tasks at the same time * } finally { * sema.release(); // Allows another waiting task to proceed. * } * } */ release() { const deferredTask = this.deferredTasks.shift(); if (deferredTask != null) { deferredTask(); return; } if (this.available < this.capacity) this.available++; } }; //#endregion export { Semaphore };