好好了解一下 EventEmitter(好好了解一下怎么回)
在 JavaScript 中,EventEmitter 是一个事件驱动编程的核心工具,用于实现对象间的发布-订阅(Pub/Sub)模式。它允许对象监听和触发自定义事件,常用于异步通信、模块解耦等场景。
1. EventEmitter 的核心概念
- 事件(Event):一个标识符(如 'message' 或 'error'),表示某种行为或状态变化。
- 监听器(Listener):绑定到事件的回调函数,当事件触发时执行。
- 触发(Emit):主动调用某个事件,执行所有绑定的监听器。
2. 原生 EventEmitter 的使用
在 Node.js 中,EventEmitter 是 events 模块的内置类。浏览器环境无原生支持,但可手动实现或使用第三方库(如 EventTarget)。
Node.js 示例
const EventEmitter = require('events');
// 创建实例
class MyEmitter extends EventEmitter {}
const emitter = new MyEmitter();
// 监听事件
emitter.on('message', (data) => {
console.log('收到消息:', data);
});
// 触发事件
emitter.emit('message', 'Hello World!'); // 输出: 收到消息: Hello World!
3. 浏览器的替代方案
(1) 使用 EventTarget(浏览器原生 API)
const eventTarget = new EventTarget();
// 监听事件
eventTarget.addEventListener('click', (e) => {
console.log('事件数据:', e.detail);
});
// 触发自定义事件
const event = new CustomEvent('click', {
detail: { x: 100, y: 200 } // 可携带数据
});
eventTarget.dispatchEvent(event);
(2) 手动实现简单 EventEmitter
class EventEmitter {
constructor() {
this.events = {}; // 存储事件及监听器
}
// 监听事件
on(eventName, listener) {
if (!this.events[eventName]) {
this.events[eventName] = [];
}
this.events[eventName].push(listener);
}
// 触发事件
emit(eventName, ...args) {
const listeners = this.events[eventName];
if (listeners) {
listeners.forEach(listener => listener(...args));
}
}
// 移除监听器
off(eventName, listenerToRemove) {
const listeners = this.events[eventName];
if (listeners) {
this.events[eventName] = listeners.filter(
listener => listener !== listenerToRemove
);
}
}
}
// 使用示例
const emitter = new EventEmitter();
emitter.on('log', (message) => {
console.log('日志:', message);
});
emitter.emit('log', '用户登录'); // 输出: 日志: 用户登录
4. EventEmitter 的关键方法
方法 | 作用 |
.on(event, listener) | 绑定事件监听器 |
.once(event, listener) | 绑定一次性监听器(触发后自动移除) |
.emit(event, [...args]) | 触发事件,并传递参数 |
.off(event, listener) | 移除指定事件的某个监听器 |
.removeAllListeners() | 移除所有监听器 |
5. 在前端代码中的用途
在之前的 WebRTC 示例中,EventEmitter 被用作信令通道的模拟,实际项目中需替换为真正的网络通信(如 WebSocket):
// 示例中的模拟信令通道
const signaling = new EventEmitter();
// 发送 Offer(模拟网络传输)
signaling.emit('offer', offerDescription);
// 接收 Answer(模拟网络接收)
signaling.on('answer', (answer) => {
pc.setRemoteDescription(answer);
});
6. 注意事项
内存泄漏
不使用的监听器需通过 .off() 主动移除,否则可能因对象无法回收导致内存泄漏。
异步触发
监听器的执行是同步的,若需异步操作,需自行封装(如用 setTimeout 或 Promise)。
错误处理
建议始终监听 'error' 事件,避免未捕获的异常导致进程崩溃(Node.js 中尤为重要):
emitter.on('error', (err) => {
console.error('发生错误:', err);
});
7. 常见应用场景
- UI 组件通信:父子组件间传递数据(如 Vue/React 中的事件总线)。
- 网络通信:封装 WebSocket 消息的发布-订阅。
- 状态管理:Redux 或 Vuex 中响应状态变化。
- 异步任务协调:多个异步操作完成后触发事件。
总结一下
EventEmitter 是 JavaScript 事件驱动编程的基石,无论是 Node.js 后端还是前端复杂交互,它都能通过解耦代码逻辑提升可维护性。实际开发中,可根据场景选择原生 API、手动实现或第三方库(如 mitt、EventEmitter3)。
爱学习的小伙伴,更多精彩,关注不迷路哟~