UNPKG

easy-action-queue

Version:

A lightweight library to queue and manage actions with configurable concurrency, supporting synchronous, asynchronous, and observable actions.

141 lines 5.5 kB
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; import { BehaviorSubject, Observable, distinctUntilChanged, firstValueFrom, } from "rxjs"; export default class EasyActionQueue { constructor(concurrency = 1) { this.concurrency = concurrency; this.queue = []; this.runningActions = new Set(); this.idleSub = new BehaviorSubject(false); this.paused = false; if (!Number.isInteger(concurrency) || concurrency < 1) { console.warn("Concurrency must be a positive integer, using 1"); this.concurrency = 1; } } // If we want idle state observable get idleObs() { return this.idleSub.asObservable().pipe(distinctUntilChanged()); } // Method to get the current queue size getQueueSize() { return this.queue.length; } // Method to update the concurrency during runtime updateConcurrency(newConcurrency) { if (!Number.isInteger(newConcurrency) || newConcurrency < 1) { throw new Error("Concurrency must be a positive integer"); } this.concurrency = newConcurrency; this.processQueue(); } // Method to pause the queue pause() { this.paused = true; } // Method to resume the queue resume() { if (this.paused) { this.paused = false; this.processQueue(); } } /** * T is type for final value, R is type of return value from the callback * action callback will be enqueued and when it gets triggered, the promise will resolve with the result * if the callback returns a string, it will be resolved in promise * if it is async operation, the result will be resolved in promise */ enqueue(action) { return __awaiter(this, void 0, void 0, function* () { this.idleSub.next(false); return new Promise((resolve, reject) => { this.queue.push({ action, resolve, reject }); this.processQueue(); }); }); } clearQueue() { const rejectAndResolve = (item) => { item.cleared = true; item.reject("EasyActionQueue has been cleared!"); }; this.runningActions.forEach(rejectAndResolve); this.runningActions.clear(); while (this.queue.length > 0) { const item = this.queue.shift(); if (item) { rejectAndResolve(item); } } this.idleSub.next(true); } processQueue() { return __awaiter(this, void 0, void 0, function* () { if (this.paused) return; while (this.runningActions.size < this.concurrency && this.queue.length > 0) { const item = this.queue.shift(); this.runningActions.add(item); try { const response = item.action(); if (response instanceof Promise) { response .then((result) => this.handleResponse(result, item)) .catch((error) => this.handleRejection(error || "Unknown error", item)); } else if (response instanceof Observable) { firstValueFrom(response) .then((result) => this.handleResponse(result, item)) .catch((error) => this.handleRejection(error || "Unknown error", item)); } else { this.handleResponse(response, item); } } catch (error) { this.handleRejection(error || "Unknown error", item); } } }); } handleResponse(result, item) { return __awaiter(this, void 0, void 0, function* () { this.handleCompletion(item, result); }); } handleRejection(error, item) { return __awaiter(this, void 0, void 0, function* () { this.handleCompletion(item, undefined, error); }); } handleCompletion(item, result, error) { return __awaiter(this, void 0, void 0, function* () { this.runningActions.delete(item); if (item.cleared) return; if (error) { item.reject(error); } else { item.resolve(result); } const lastIdleState = yield firstValueFrom(this.idleObs); if (this.runningActions.size === 0 && this.queue.length === 0 && !lastIdleState) { this.idleSub.next(true); } this.processQueue(); }); } } //# sourceMappingURL=ActionQueue.js.map