power-tasks
Version:
Powerful task management for JavaScript
92 lines (91 loc) • 2.74 kB
JavaScript
import DoublyLinked from "doublylinked";
import { AsyncEventEmitter } from "strict-typed-events";
import { Task } from "./task.js";
export class TaskQueue extends AsyncEventEmitter {
constructor(options) {
super();
this._queue = new DoublyLinked();
this._running = new Set();
this.maxQueue = options?.maxQueue;
this.concurrency = options?.concurrency;
this._paused = !!options?.paused;
}
get size() {
return this._queue.length + this._running.size;
}
get running() {
return this._running.size;
}
get queued() {
return this._queue.length;
}
get paused() {
return this._paused;
}
pause() {
this._paused = true;
}
resume() {
this._paused = false;
setImmediate(() => this._pulse());
}
clearQueue() {
this._queue.forEach((task) => task.abort());
this._queue = new DoublyLinked();
}
abortAll() {
if (!this.size)
return;
this.clearQueue();
this._running.forEach((task) => task.abort());
}
async wait() {
if (!this.size)
return Promise.resolve();
return new Promise((resolve) => {
this.once("finish", resolve);
});
}
enqueuePrepend(task) {
return this._enqueue(task, true);
}
enqueue(task) {
return this._enqueue(task, false);
}
_enqueue(task, prepend) {
if (this.maxQueue && this.size >= this.maxQueue)
throw new Error(`Queue limit (${this.maxQueue}) exceeded`);
const taskInstance = task instanceof Task ? task : new Task(task);
Object.defineProperty(taskInstance, "_isManaged", {
configurable: false,
writable: false,
enumerable: false,
value: true,
});
taskInstance.once("error", (...args) => this.emitAsync("error", ...args));
this.emit("enqueue", taskInstance);
if (prepend)
this._queue.unshift(taskInstance);
else
this._queue.push(taskInstance);
this._pulse();
return taskInstance;
}
_pulse() {
if (this.paused)
return;
while (!this.concurrency || this._running.size < this.concurrency) {
const task = this._queue.shift();
if (!task)
return;
this._running.add(task);
task.prependOnceListener("finish", () => {
this._running.delete(task);
if (!(this._running.size || this._queue.length))
return this.emit("finish");
this._pulse();
});
task.start();
}
}
}