UNPKG

evnty

Version:

Async-first, reactive event handling library for complex event flows in browser and Node.js

105 lines (103 loc) 2.93 kB
import { err } from "./dispatch-result.js"; export class ListenerRegistry { #listeners = new Map(); #snapshot = null; [Symbol.toStringTag] = 'ListenerRegistry'; get size() { return this.#listeners.size; } has(listener) { return this.#listeners.has(listener); } lacks(listener) { return !this.has(listener); } off(listener) { const entry = this.#listeners.get(listener); if (!entry) { return false; } this.#listeners.delete(listener); this.#snapshot = null; entry.onRemove?.(); return true; } on(listener, onRemove) { if (this.has(listener)) { return false; } this.#listeners.set(listener, { once: false, onRemove }); this.#snapshot = null; return true; } once(listener, onRemove) { if (this.has(listener)) { return false; } this.#listeners.set(listener, { once: true, onRemove }); this.#snapshot = null; return true; } clear() { for (const entry of this.#listeners.values()){ entry.onRemove?.(); } this.#listeners.clear(); this.#snapshot = null; } dispatch(...values) { const listeners = this.#listeners; if (listeners.size === 0) { return []; } let ordered = this.#snapshot; if (!ordered) { const snapshot = new Array(listeners.size); let index = 0; for (const fn of listeners.keys()){ snapshot[index++] = fn; } snapshot.length = index; ordered = snapshot; this.#snapshot = snapshot; } if (ordered.length === 0) { return []; } const results = new Array(ordered.length); const argCount = values.length; for(let index = 0; index < ordered.length; index++){ const fn = ordered[index]; if (listeners.get(fn)?.once) { this.off(fn); } const invoke = fn; try { switch(argCount){ case 0: results[index] = invoke(); break; case 1: results[index] = invoke(values[0]); break; case 2: results[index] = invoke(values[0], values[1]); break; default: results[index] = invoke(...values); break; } } catch (error) { results[index] = err(error); } } return results; } } //# sourceMappingURL=listener-registry.js.map