@nostr-dev-kit/ndk
Version:
NDK - Nostr Development Kit. Includes AI Guardrails to catch common mistakes during development.
90 lines (75 loc) • 2.36 kB
text/typescript
type QueueItem<T> = {
/**
* Deterministic id of the item
*/
id: string;
/**
* A function to process the item
* @returns
*/
func: () => Promise<T>;
};
export class Queue<T> {
private queue: QueueItem<T>[] = [];
private maxConcurrency: number;
private processing: Set<string> = new Set();
private promises: Map<string, Promise<T>> = new Map();
constructor(_name: string, maxConcurrency: number) {
this.maxConcurrency = maxConcurrency;
}
public add(item: QueueItem<T>): Promise<T> {
if (this.promises.has(item.id)) {
return this.promises.get(item.id)!;
}
const promise = new Promise<T>((resolve, reject) => {
this.queue.push({
...item,
func: () =>
item.func().then(
(result) => {
resolve(result);
return result; // Return the result to match the expected type.
},
(error) => {
reject(error);
// It's important to rethrow the error here to not accidentally resolve the promise.
// However, since TypeScript 4.4, you can set "useUnknownInCatchVariables" to false if this line errors.
throw error;
},
),
});
this.process();
});
this.promises.set(item.id, promise);
promise.finally(() => {
this.promises.delete(item.id);
this.processing.delete(item.id);
this.process();
});
return promise;
}
private process() {
if (this.processing.size >= this.maxConcurrency || this.queue.length === 0) {
return;
}
const item = this.queue.shift();
if (!item || this.processing.has(item.id)) {
return;
}
this.processing.add(item.id);
item.func();
}
public clear() {
this.queue = [];
}
public clearProcessing() {
this.processing.clear();
}
public clearAll() {
this.clear();
this.clearProcessing();
}
public length() {
return this.queue.length;
}
}