Node.js EventEmitter
发布订阅、once、错误事件、监听器泄漏。
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
只执行一次
发邮件 1002API 一览
| Method | Meaning |
|---|---|
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.
基本用法
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
只执行一次
发邮件 1002API 一览
| 方法 | 含义 |
|---|---|
on / addListener | 持续监听 |
once | 触发一次后自动移除 |
off / removeListener | 移除指定监听器 |
removeAllListeners | 清空 |
emit | 同步触发,返回是否有监听器 |
listenerCount | 当前监听器数量 |
setMaxListeners | 调整告警阈值(默认 10) |
emit 是同步的:监听器按注册顺序依次执行完,emit 才返回。这跟浏览器 DOM 事件不同,DOM 事件是异步派发的。
错误事件
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') 没有监听器时抛出的是未捕获异常,会直接终止进程。给每个自定义 EventEmitter 加 'error' 监听器是硬性要求。内存泄漏
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 就是这个问题。别急着 setMaxListeners(0) 关掉警告——那是掩盖症状。