EventEmitter 事件发射器
TypeScript无框架依赖EventEmitter 是一个轻量级的事件发射器,提供完整的事件发布-订阅机制。支持一次性事件监听、精准移除、批量清除等功能。
特性
- 类型安全 — 通过泛型约束事件名,支持事件的类型安全触发
- 一次性监听 —
onOnce注册的事件执行一次后自动移除 - 精准移除 —
off可精确移除指定事件的指定回调 - 批量清除 —
clear清除指定事件、clearAll清除所有事件 - 错误隔离 — 单个回调抛出异常不影响其他回调的执行
- 快照安全 —
emit内部使用Array.from快照遍历,避免嵌套 emit 或回调中移除监听导致遍历异常
接口
ts
class EventEmitter<EventName extends string> {
/** 注册事件监听器 */
on(eventName: EventName, cb: (...args: any[]) => void): (...args: any[]) => void;
/** 注册事件监听器,仅执行一次后自动移除 */
onOnce(eventName: EventName, cb: (...args: any[]) => void): (...args: any[]) => void;
/** 触发事件,传递参数给所有已注册的回调 */
emit(eventName: EventName, ...args: any[]): void;
/** 移除指定事件的指定监听器 */
off(eventName: EventName, cb: (...args: any[]) => void): void;
/** 移除指定事件的所有监听器 */
clear(eventName: EventName): void;
/** 移除所有事件的所有监听器 */
clearAll(): void;
/** 获取所有已注册事件名称 */
getAllListeners(): EventName[];
}使用示例
基础用法
ts
import { EventEmitter } from 'howie-daily-helpers-core';
const emitter = new EventEmitter<'open' | 'close' | 'data'>();
// 注册事件
emitter.on('open', () => {
console.log('连接已打开');
});
// 触发事件
emitter.emit('open');
// 输出: 连接已打开传递参数
ts
emitter.on('data', (payload: { id: number; name: string }) => {
console.log('收到数据:', payload.id, payload.name);
});
emitter.emit('data', { id: 1, name: 'Alice' });
// 输出: 收到数据: 1 Alice一次性监听
ts
emitter.onOnce('open', () => {
console.log('首次打开(仅执行一次)');
});
emitter.emit('open'); // 输出: 首次打开(仅执行一次)
emitter.emit('open'); // 不再输出移除监听器
ts
const handler = () => console.log('处理中');
emitter.on('data', handler);
emitter.off('data', handler); // 移除后不再触发
emitter.emit('data'); // 无输出批量清除
ts
emitter.on('open', handler1);
emitter.on('close', handler2);
// 清除指定事件
emitter.clear('open');
emitter.emit('open'); // 无输出
// 清除所有事件
emitter.clearAll();
emitter.emit('close'); // 无输出获取已注册事件
ts
emitter.on('open', handler1);
emitter.on('close', handler2);
console.log(emitter.getAllListeners()); // ['open', 'close']工作原理
- 内部使用
Map<EventName, Set<CB>>存储事件名到回调集合的映射,利用Set保证回调不重复注册 onOnce除注册到events外,还会在独立的onceEvents中记录,emit遍历时自动判断是否需要移除emit中使用Array.from(set)创建快照再遍历,避免在回调中嵌套emit或调用off导致遍历行为异常- 单个回调的异常被
try-catch捕获并通过logger.error输出,不影响其他回调执行
典型场景
- 跨组件/跨模块的事件通信
- 插件系统的生命周期管理
- 异步操作的状态通知(如 WebSocket 连接状态)
- 作为基础构件用于更复杂的发布-订阅模式实现