Created
August 21, 2022 18:01
-
-
Save matthew-e-brown/b048bf62eeada3bae247bbb374e6b12a to your computer and use it in GitHub Desktop.
TypeScript Promise Queue
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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(); | |
| }); | |
| } | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Adapted to TS from JS from a Medium article by markosyan.