| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374 |
- interface EventListener<T = unknown> {
- callback: (payload: T) => void;
- target?: unknown;
- once: boolean;
- }
- export class EventManager<TEvents extends object = Record<string, unknown>> {
- private readonly listeners = new Map<keyof TEvents, Set<EventListener>>();
- on<K extends keyof TEvents>(event: K, callback: (payload: TEvents[K]) => void, target?: unknown): void {
- this.add(event, callback, target, false);
- }
- once<K extends keyof TEvents>(event: K, callback: (payload: TEvents[K]) => void, target?: unknown): void {
- this.add(event, callback, target, true);
- }
- off<K extends keyof TEvents>(event: K, callback: (payload: TEvents[K]) => void, target?: unknown): void {
- const bucket = this.listeners.get(event);
- if (!bucket) return;
- for (const listener of bucket) {
- if (listener.callback === callback && listener.target === target) {
- bucket.delete(listener);
- }
- }
- if (bucket.size === 0) this.listeners.delete(event);
- }
- offTarget(target: unknown): void {
- for (const [event, bucket] of this.listeners) {
- for (const listener of bucket) {
- if (listener.target === target) bucket.delete(listener);
- }
- if (bucket.size === 0) this.listeners.delete(event);
- }
- }
- emit<K extends keyof TEvents>(event: K, payload?: TEvents[K]): void {
- const bucket = this.listeners.get(event);
- if (!bucket) return;
- for (const listener of [...bucket]) {
- try {
- (listener.callback as (value: TEvents[K]) => void).call(listener.target, payload);
- } catch (error) {
- console.error(`[EventManager] listener failed: ${String(event)}`, error);
- }
- if (listener.once) bucket.delete(listener);
- }
- if (bucket.size === 0) this.listeners.delete(event);
- }
- clear(): void {
- this.listeners.clear();
- }
- private add<K extends keyof TEvents>(event: K, callback: (payload: TEvents[K]) => void, target: unknown, once: boolean): void {
- let bucket = this.listeners.get(event);
- if (!bucket) {
- bucket = new Set<EventListener>();
- this.listeners.set(event, bucket);
- }
- for (const listener of bucket) {
- if (listener.callback === callback && listener.target === target) return;
- }
- bucket.add({ callback: callback as (payload: unknown) => void, target, once });
- }
- }
|