Skip to content

Instantly share code, notes, and snippets.

@matthew-e-brown
Created August 21, 2022 18:01
Show Gist options
  • Select an option

  • Save matthew-e-brown/b048bf62eeada3bae247bbb374e6b12a to your computer and use it in GitHub Desktop.

Select an option

Save matthew-e-brown/b048bf62eeada3bae247bbb374e6b12a to your computer and use it in GitHub Desktop.
TypeScript Promise Queue
class QueuePoppedError extends Error {
constructor(message?: string) {
super(message);
}
}
interface QueuedPromise<T> {
runner: () => Promise<T>;
resolver: (value: T | PromiseLike<T>) => void;
rejecter: (reason: any) => void;
}
export class PromiseQueue {
private queue: QueuedPromise<unknown>[];
private waiting: boolean;
private maxSize: number;
public constructor(maxSize: number = Infinity) {
this.queue = [ ];
this.waiting = false;
this.maxSize = maxSize;
}
/**
* Slates a promise for execution.
* @param {() => Promise<T>} runner A function that will call your function
* when the queue is ready to begin executing it.
* @return {Promise<T>} The result of the promise executed by `runner`.
*/
public enqueue<T>(runner: () => Promise<T>): Promise<T> {
return new Promise<unknown>((resolver, rejecter) => {
// If we reached the max size, pop the oldest one off the stack
if (this.queue.length >= this.maxSize) {
const popped = this.queue.shift();
popped?.rejecter(new QueuePoppedError());
}
this.queue.push({
runner,
resolver,
rejecter,
});
// Attempt to immediately pop this one off the queue
this.dequeue();
}) as Promise<T>;
}
private dequeue(): void {
// If another promise is already running, don't run this yet
if (this.waiting) return;
const item = this.queue.shift();
// If there are no more promises to run, we have nothing to do
if (!item) return;
// Run this promise
this.waiting = true;
item.runner()
.then(item.resolver)
.catch(item.rejecter)
.finally(() => {
// Attempt to run the next one
this.waiting = false;
this.dequeue();
});
}
}
@matthew-e-brown
Copy link
Author

Adapted to TS from JS from a Medium article by markosyan.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment