Node.js EventEmitter

发布订阅、once、错误事件、监听器泄漏。

Intermediate
Key Points`'error'` 事件没有监听器会直接抛异常;监听器超过 10 个会警告。

基本用法

JavaScript
const { EventEmitter } = require('node:events');

const bus = new EventEmitter();

bus.on('order:paid', (order) => {
  console.log('发邮件', order.id);
});
bus.once('order:paid', () => {
  console.log('只执行一次');
});

bus.emit('order:paid', { id: 1001 });
bus.emit('order:paid', { id: 1002 });
Output
发邮件 1001
只执行一次
发邮件 1002

API 一览

MethodMeaning
on / addListener持续监听
once触发一次后自动移除
off / removeListener移除指定监听器
removeAllListeners清空
emit同步触发,返回是否有监听器
listenerCount当前监听器数量
setMaxListeners调整告警阈值(默认 10)

emit is synchronous: listeners run in registration order and only then does emit return. Unlike DOM events, which dispatch asynchronously.

错误事件

JavaScript
const bus = new EventEmitter();

// 没有 error 监听器 → 抛异常,进程可能退出
try {
  bus.emit('error', new Error('磁盘满了'));
} catch (e) {
  console.log('捕获:', e.message);
}

// 有监听器 → 走监听器
bus.on('error', (e) => console.log('处理:', e.message));
bus.emit('error', new Error('连接断开'));
Output
捕获: 磁盘满了
处理: 连接断开
emit('error') with no listener throws an uncaught exception and terminates the process. Always attach an 'error' listener to custom emitters.

内存泄漏

JavaScript
// 每次请求都 on,永远不 off → 监听器无限增长
app.get('/x', (req, res) => {
  bus.on('tick', () => res.write('.'));
});

// 正确:用 once 或在请求结束时移除
app.get('/y', (req, res) => {
  const h = () => res.write('.');
  bus.on('tick', h);
  req.on('close', () => bus.off('tick', h));
});

MaxListenersExceededWarning: Possible EventEmitter memory leak detected is exactly this. Do not silence it with setMaxListeners(0) — that hides the symptom.

Friends & Partners