UNPKG

nope-js-browser

Version:

NoPE Runtime for the Browser. For nodejs please use nope-js-node

139 lines (138 loc) 4.19 kB
import { NopePromise } from "../promise"; import { isAsyncFunction } from "./async"; import { PriorityList } from "./lists"; /** * A Task-Queue. This could be used to make parallel * Request run sequentially. For Instance during * Saving and Reading Vars to achive a consistent set * of Data. * * Usage: * * ```typescript * // Create a Queue * const _queue = new PriorityTaskQueue(); * // Create a Function * const _func = (_input: string, _cb) => { * console.log("Hallo ", _input) * _cb(null, null); * } * * const promises = [ * _queue.execute(_func, ['Welt priority=0'],0), * _queue.execute(_func, ['Welt priority=1'],1), * _queue.execute(_func, ['Welt priority=2'],2) * * ]; * * // => Hallo Welt priority=0 <- Startet directly. * // => Hallo Welt priority=2 <- Startet because it has the highest priority. * // => Hallo Welt priority=1 * ``` * @export * @class TaskQeue */ export class ParallelPriorityTaskQueue { constructor() { this._queue = new PriorityList(); this._runningTasks = 0; this._counter = 0; this.maxParallel = 1; this.usePriority = true; } /** * Executes the given Task. If now Task is running it is executed immediatelly, * otherwise it is pushed in the queue and call if the other tasks are call. * * @param {any} _func The Function which should be called. * @param {any} _param The Data which should be used for the call. * @param {any} _callback The Callback, which should be called after * @memberof TaskQeue */ execute(func, args, priority = 0, cancel = () => { }) { let resolve, reject; const promise = new NopePromise((res, rej) => { resolve = res; reject = rej; }); promise.cancel = cancel; // Check whether the Execution is activ: if (this._runningTasks < this.maxParallel && this._queue.length < this.maxParallel) { this._runningTasks++; this._execute({ func, args, cancel, resolve, reject, }); } else { // Extend the Queue. this._queue.push(this.usePriority ? priority : this._counter++, { func, args, cancel, resolve, reject, }); } return promise; } _execute(data) { // Verify whether there is an CancelHandler, if yes. // Register at the Cancel-Handler. Thereby the next // function is call if the currently running Task is // aborted. if (data.cancel) { data.args.push(() => { data.cancel(); data.reject(Error("Canceled")); this._finish(); }); } if (isAsyncFunction(data.func)) { data.func(...data.args) .then((res) => { data.resolve(res); this._finish(); }) .catch((err) => { data.reject(err); this._finish(); }); } else { try { const res = data.func(...data.args); data.resolve(res); } catch (err) { data.reject(err); } this._finish(); } } /** * Internal Function to Finish all Tasks. * * @protected * @memberof PriorityTaskQueue */ _finish() { // Remove one Element. this._runningTasks--; if (this._runningTasks < 0) { this._runningTasks = 0; } // Remove the First Task const task = this._queue.highest(); // Call the Function with the adapted Callback, if there is a Task Left open. if (task) { this._execute(task); } } get length() { return this._queue.length; } }