Node.js自定义EventEmitter如何监听preventDefault以控制默认逻辑执行
解决方案
核心逻辑:Node.js 的 EventEmitter 触发事件时,同步监听器会按注册顺序依次执行完毕后才会返回,因此我们可以主动构造可取消事件对象作为入参传给监听器,事件触发完成后直接读取该对象的属性即可判断是否需要执行默认逻辑,比现有方案更简洁且逻辑正确。
基础实现(同步监听器场景,覆盖90%使用场景)
第一步:定义可取消事件类
class CancelableEvent { // 标记是否已经阻止默认行为 public defaultPrevented = false; // 暴露阻止默认行为的方法 public preventDefault(): void { this.defaultPrevented = true; } }
TypeScript 场景下可以补充事件接口定义,获得更好的类型提示:
interface MyClassEvents { 'will-quit': (event: CancelableEvent) => void; } class MyClass extends EventEmitter<MyClassEvents> { // 类实现 }
第二步:改写close方法逻辑
class MyClass extends EventEmitter { close(winID: number): void { // 1. 初始化可取消事件实例 const willQuitEvent = new CancelableEvent(); // 2. 触发事件,将事件对象传给所有监听器 this.emit('will-quit', willQuitEvent); // 3. 所有同步监听器执行完毕,直接判断是否要执行默认关闭 if (!willQuitEvent.defaultPrevented) { app.close(winID); } } }
监听器使用示例
和标准DOM事件用法完全一致,无额外学习成本:
const instance = new MyClass(); instance.on('will-quit', (event) => { // 满足业务条件时阻止默认关闭 if (hasUnsavedChanges()) { event.preventDefault(); alert('存在未保存内容,无法关闭'); } });
扩展实现(支持异步监听器场景)
如果业务中存在异步的 will-quit 监听器(比如需要异步请求后端判断是否允许关闭),可以调整为等待所有异步监听器执行完成后再判断:
class MyClass extends EventEmitter { async close(winID: number): Promise<void> { const willQuitEvent = new CancelableEvent(); // 手动遍历所有监听器,收集异步返回值 const listeners = this.listeners('will-quit') as Array<(e: CancelableEvent) => void | Promise<void>>; // 等待所有监听器执行完成 await Promise.all(listeners.map(listener => listener(willQuitEvent))); if (!willQuitEvent.defaultPrevented) { app.close(winID); } } }
原有方案的问题说明
你之前的实现存在逻辑缺陷:EventEmitter 的监听器执行顺序和注册顺序完全一致,先注册的 once 回调会先于所有已经注册的业务监听器执行,此时业务逻辑还没调用 preventDefault,判断结果永远是未阻止,达不到预期效果。
内容的提问来源于stack exchange,提问作者Computroniks
相关产品推荐
相关产品推荐

