@v4fire/client
Version:
V4Fire client core library
122 lines (100 loc) • 2.65 kB
text/typescript
/*!
* 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);
}
}
}