EventManager.ts 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. interface EventListener<T = unknown> {
  2. callback: (payload: T) => void;
  3. target?: unknown;
  4. once: boolean;
  5. }
  6. export class EventManager<TEvents extends object = Record<string, unknown>> {
  7. private readonly listeners = new Map<keyof TEvents, Set<EventListener>>();
  8. on<K extends keyof TEvents>(event: K, callback: (payload: TEvents[K]) => void, target?: unknown): void {
  9. this.add(event, callback, target, false);
  10. }
  11. once<K extends keyof TEvents>(event: K, callback: (payload: TEvents[K]) => void, target?: unknown): void {
  12. this.add(event, callback, target, true);
  13. }
  14. off<K extends keyof TEvents>(event: K, callback: (payload: TEvents[K]) => void, target?: unknown): void {
  15. const bucket = this.listeners.get(event);
  16. if (!bucket) return;
  17. for (const listener of bucket) {
  18. if (listener.callback === callback && listener.target === target) {
  19. bucket.delete(listener);
  20. }
  21. }
  22. if (bucket.size === 0) this.listeners.delete(event);
  23. }
  24. offTarget(target: unknown): void {
  25. for (const [event, bucket] of this.listeners) {
  26. for (const listener of bucket) {
  27. if (listener.target === target) bucket.delete(listener);
  28. }
  29. if (bucket.size === 0) this.listeners.delete(event);
  30. }
  31. }
  32. emit<K extends keyof TEvents>(event: K, payload?: TEvents[K]): void {
  33. const bucket = this.listeners.get(event);
  34. if (!bucket) return;
  35. for (const listener of bucket.values()) {
  36. try {
  37. (listener.callback as (value: TEvents[K]) => void).call(listener.target, payload);
  38. } catch (error) {
  39. console.error(`[EventManager] listener failed: ${String(event)}`, error, listener);
  40. }
  41. if (listener.once) bucket.delete(listener);
  42. }
  43. if (bucket.size === 0) this.listeners.delete(event);
  44. }
  45. clear(): void {
  46. this.listeners.clear();
  47. }
  48. private add<K extends keyof TEvents>(event: K, callback: (payload: TEvents[K]) => void, target: unknown, once: boolean): void {
  49. if (typeof callback !== 'function') {
  50. console.error(`[EventManager] ignored invalid listener: ${String(event)}`);
  51. return;
  52. }
  53. let bucket = this.listeners.get(event);
  54. if (!bucket) {
  55. bucket = new Set<EventListener>();
  56. this.listeners.set(event, bucket);
  57. }
  58. for (const listener of bucket) {
  59. if (listener.callback === callback && listener.target === target) return;
  60. }
  61. bucket.add({ callback: callback as (payload: unknown) => void, target, once });
  62. }
  63. }