UNPKG

@v4fire/client

Version:

V4Fire client core library

122 lines (100 loc) 2.65 kB
/*! * V4Fire Client Core * https://github.com/V4Fire/Client * * Released under the MIT license * https://github.com/V4Fire/Client/blob/master/LICENSE */ /** * [[include:core/component/queue-emitter/README.md]] * @packageDocumentation */ import type { EventListener } from 'core/component/queue-emitter/interface'; export * from 'core/component/queue-emitter/interface'; /** * The special kind of event emitter that supports queues of events */ export default class QueueEmitter { /** * Queue of event listeners that is ready to fire */ protected queue: Function[] = []; /** * Map of tied event listeners that isn't ready to fire */ protected listeners: Dictionary<EventListener[]> = Object.createDict(); /** * Attaches a callback for the specified set of events. * The callback will be invoked only when all specified events was emitted. * * @param event - set of events (can be undefined) * @param cb */ on(event: Nullable<Set<string>>, cb: Function): void { if (event != null && event.size > 0) { for (let v = event.values(), el = v.next(); !el.done; el = v.next()) { const key = el.value; this.listeners[key] = this.listeners[key] ?? []; this.listeners[key]!.push({event, cb}); } return; } this.queue.push(cb); } /** * Emits the specified event. * If at least one of listeners returns a promise, * the method returns promise that is resolved after all internal promises are resolved. * * @param event */ emit(event: string): CanPromise<void> { const queue = this.listeners[event]; if (!queue) { return; } const tasks = <Array<CanPromise<unknown>>>[]; for (let i = 0; i < queue.length; i++) { const el = queue[i]; // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if (el != null) { const ev = el.event; ev.delete(event); if (ev.size === 0) { const task = el.cb(); if (Object.isPromise(task)) { tasks.push(task); } } } } if (tasks.length > 0) { return Promise.all(tasks).then(() => undefined); } } /** * Drains the queue of listeners that is ready to fire. * If at least one of listeners returns a promise, * the method returns promise that is resolved after all internal promises are resolved. */ drain(): CanPromise<void> { const {queue} = this; const tasks = <Array<Promise<unknown>>>[]; for (let i = 0; i < queue.length; i++) { const task = queue[i](); if (Object.isPromise(task)) { tasks.push(task); } } if (tasks.length > 0) { return Promise.all(tasks).then(() => undefined); } } }