@daiso-tech/core
Version:
The library offers flexible, framework-agnostic solutions for modern web applications, built on adaptable components that integrate seamlessly with popular frameworks like Next Js.
107 lines • 3.03 kB
JavaScript
/**
* @module Async
*/
import {} from "../../../utilities/_module-exports.js";
import { LazyPromise } from "../../../async/utilities/_module.js";
import { v4 } from "uuid";
import { CapacityFullAsyncError } from "../../../async/async.errors.js";
/**
* @internal
*/
class Queue {
array = [];
size() {
return this.array.length;
}
enqueue(value) {
this.array.push(value);
}
dequeue() {
return this.array.shift() ?? null;
}
}
/**
* @internal
*/
export class PromiseQueue {
settings;
queue = new Queue();
listeners = new Map();
constructor(settings) {
this.settings = settings;
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.start();
}
async start() {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition, no-constant-condition
while (true) {
await Promise.all(this.getItems().map((item) => this.process(item)));
await LazyPromise.delay(this.settings.interval);
}
}
getItems() {
const values = [];
for (let i = 0; i < this.settings.maxConcurrency; i++) {
const item = this.queue.dequeue();
if (item === null) {
continue;
}
values.push(item);
}
return values;
}
async process(item) {
const listener = this.listeners.get(item.id);
try {
if (item.signal.aborted) {
listener?.([null, item.signal.reason]);
return;
}
const value = await item.func(item.signal);
listener?.([value, null]);
}
catch (error) {
listener?.([null, error]);
throw error;
}
}
enqueue(func, signal) {
const id = v4();
if (this.settings.maxCapacity === null) {
this.queue.enqueue({
id,
func,
signal,
});
}
else if (this.queue.size() <= this.settings.maxCapacity) {
this.queue.enqueue({ id, func, signal });
}
else {
throw new CapacityFullAsyncError(`Max capacity reached, ${String(this.settings.maxCapacity)} items allowed.`);
}
return id;
}
listenOnce(id, listener) {
this.listeners.set(id, listener);
}
asPromise(id) {
return new Promise((resolve, reject) => {
this.listenOnce(id, ([value, error]) => {
if (value === null) {
// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors
reject(error);
return;
}
resolve(value);
});
});
}
/**
* @throws {CapacityFullAsyncError} {@link CapacityFullAsyncError}
*/
add(func, signal) {
return this.asPromise(this.enqueue(func, signal));
}
}
//# sourceMappingURL=promise-queue.js.map