全部学科
Python全栈
python
NodeJS全栈
nodejs
小程序首页
📅 2026-05-15 9 分钟 ✍️ juanwangdev

Node.js 事件驱动与EventEmitter深入

事件驱动模式让 Node.js 能高效处理并发 I/O,EventEmitter 是其核心实现。

EventEmitter 内部结构

JavaScript
const EventEmitter = require('events');

// EventEmitter 内部存储
// _events: { eventName: [listener1, listener2, ...] }
// _eventsCount: 监听器总数
// _maxListeners: 最大监听器数量(默认 10)

const emitter = new EventEmitter();
emitter.on('data', () => {});
emitter.on('data', () => {});

console.log(emitter._events);
// { data: [Function, Function] }

监听器执行顺序

JavaScript
// 监听器按添加顺序执行
const emitter = new EventEmitter();

emitter.on('event', () => console.log('A'));
emitter.on('event', () => console.log('B'));
emitter.on('event', () => console.log('C'));

emitter.emit('event');
// 输出: A -> B -> C

// prependListener 添加到头部
emitter.prependListener('event', () => console.log('D'));
// D -> A -> B -> C

emit 执行机制

JavaScript
// emit 同步执行所有监听器
const emitter = new EventEmitter();

emitter.on('sync', () => {
  console.log('监听器1');
});

console.log('开始');
emitter.emit('sync');
console.log('结束');

// 输出: 开始 -> 监听器1 -> 结束
// emit 是同步调用,不是异步

异步事件模式

JavaScript
// 异步执行监听器
emitter.on('async', (data) => {
  setImmediate(() => {
    console.log('异步处理:', data);
  });
});

// 或使用 Promise
emitter.on('async', async (data) => {
  await processData(data);
});

error 事件处理

JavaScript
// error 事件必须处理
const emitter = new EventEmitter();

// ❌ 未监听 error,进程崩溃
// emitter.emit('error', new Error('错误'));

// ✅ 监听 error 事件
emitter.on('error', (err) => {
  console.error('捕获错误:', err.message);
});

emitter.emit('error', new Error('测试错误'));

// 全局 error 处理
EventEmitter.defaultMaxListeners = 20;

// 捕获未处理的 error
process.on('uncaughtException', (err) => {
  console.error('未捕获异常:', err);
});

once 一次性监听器

JavaScript
// once 执行一次后自动移除
const emitter = new EventEmitter();

emitter.once('connect', () => {
  console.log('首次连接');
});

emitter.emit('connect'); // 输出: 首次连接
emitter.emit('connect'); // 无输出

// once 内部实现
// 包装 listener,执行后调用 removeListener

监听器移除

JavaScript
// 移除监听器需相同引用
function handler() {
  console.log('handler');
}

emitter.on('data', handler);
emitter.removeListener('data', handler); // 成功

// ❌ 匿名函数无法移除
emitter.on('data', () => {});
emitter.removeListener('data', () => {}); // 失败,不同引用

// 使用 off 别名(Node.js 10+)
emitter.off('data', handler);

监听器数量限制

JavaScript
// 默认最多 10 个监听器
emitter.on('data', () => {});
// ... 添加超过 10 个会警告

// 设置最大数量
emitter.setMaxListeners(20);

// 获取最大数量
console.log(emitter.getMaxListeners());

// 全局设置
EventEmitter.defaultMaxListeners = 20;

// 无限制(谨慎使用)
emitter.setMaxListeners(0);

自定义事件类

JavaScript
class Database extends EventEmitter {
  connect() {
    // 模拟连接
    setTimeout(() => {
      this.emit('connected');
    }, 1000);
  }

  query(sql) {
    setTimeout(() => {
      this.emit('query', { sql, result: [] });
    }, 500);
  }

  close() {
    this.emit('closed');
    this.removeAllListeners();
  }
}

const db = new Database();

db.on('connected', () => console.log('已连接'));
db.on('query', (data) => console.log('查询:', data.sql));
db.on('closed', () => console.log('已关闭'));

db.connect();
db.query('SELECT * FROM users');

事件命名规范

JavaScript
// 推荐命名
emitter.emit('connection:established');
emitter.emit('user:login');
emitter.emit('data:received');
emitter.emit('error:network');

// 避免冲突
const EVENTS = {
  CONNECT: 'connect',
  DISCONNECT: 'disconnect',
  ERROR: 'error',
  DATA: 'data'
};

emitter.on(EVENTS.CONNECT, handler);
emitter.emit(EVENTS.CONNECT);

EventEmitter 性能考量

JavaScript
// 大量监听器影响性能
// 监听器越多,emit 越慢

// 优化:合并相关事件
emitter.on('user', (action, data) => {
  switch (action) {
    case 'login': handleLogin(data);
    case 'logout': handleLogout(data);
  }
});

// 避免:大量独立事件
emitter.on('user:login', handler);
emitter.on('user:logout', handler);
// ... 多个事件

捕获所有事件

JavaScript
// 使用 newListener 监听添加
emitter.on('newListener', (event, listener) => {
  console.log('添加监听器:', event);
});

// 使用 removeListener 监听移除
emitter.on('removeListener', (event, listener) => {
  console.log('移除监听器:', event);
});

// 使用 '*' 捕获所有事件(需自定义)
class WildcardEmitter extends EventEmitter {
  emit(event, ...args) {
    super.emit('*', event, ...args);
    super.emit(event, ...args);
  }
}

要点总结

  • EventEmitter 内部用 _events 对象存储监听器
  • emit 同步执行所有监听器,非异步
  • 监听器按添加顺序执行,prependListener 可前置
  • error 事件未监听会导致进程崩溃
  • 监听器数量默认限制 10,setMaxListeners 调整
  • 移除监听器需传入相同函数引用

📝 发现内容有误?点击此处直接编辑

← 上一篇 Node.js 事件循环机制深度解析
下一篇 → Node.js 定时器与延迟执行
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库