UNPKG

@augment-vir/common

Version:

A collection of augments, helpers types, functions, and classes for any JavaScript environment.

92 lines (91 loc) 2.98 kB
import { check } from '@augment-vir/assert'; import { DeferredPromise } from '@augment-vir/core'; import { defineTypedCustomEvent, ListenTarget } from 'typed-event-target'; /** * The event emitted from a {@link PromiseQueue} instance whenever the queue is updated (an item is * resolved or an item is added). * * @category Promise : Util * @category Package : @augment-vir/common * @package [`@augment-vir/common`](https://www.npmjs.com/package/@augment-vir/common) */ export class PromiseQueueUpdateEvent extends defineTypedCustomEvent()('promise-queue-update') { } /** * A queue that manages its items with promises. * * @category Promise * @category Package : @augment-vir/common * @package [`@augment-vir/common`](https://www.npmjs.com/package/@augment-vir/common) */ export class PromiseQueue extends ListenTarget { queue = []; currentlyAwaiting = undefined; /** The current size of the queue. */ get size() { return this.queue.length; } /** * Add an item to the queue. * * @returns A promise that resolves at the same time as the added item. */ add(item) { const newItem = { original: item, wrapper: new DeferredPromise(), }; this.queue.push(newItem); this.dispatch(new PromiseQueueUpdateEvent({ detail: { queueSize: this.size, addedItem: newItem, }, })); this.triggerNextQueueItem(); return newItem.wrapper.promise; } /** Handles a queue item finishing, whether it be a rejection or a resolution. */ handleItemSettle({ rejection, resolution, }) { const item = this.currentlyAwaiting; if (!item) { throw new Error(`Cannot handle queue item settle without a currently awaited queue item.`); } this.queue.splice(0, 1); this.dispatch(new PromiseQueueUpdateEvent({ detail: { queueSize: this.size, finishedItem: item, }, })); if (rejection) { item.wrapper.reject(rejection); } else { item.wrapper.resolve(resolution); } this.currentlyAwaiting = undefined; this.triggerNextQueueItem(); return item; } /** * Tries to trigger the next queue item, if there is one. * * @returns Whether a new queue item was triggered or not. `true` if it was, otherwise `false`. */ triggerNextQueueItem() { if (this.currentlyAwaiting || !check.isLengthAtLeast(this.queue, 1)) { return false; } const item = this.queue[0]; this.currentlyAwaiting = item; item.original() .then((result) => { this.handleItemSettle({ resolution: result }); }) .catch((error) => { this.handleItemSettle({ rejection: error }); }); return true; } }