做什么
Node 的事件机制——许多内置对象(HTTP server、Stream、process)都基于 EventEmitter。
import { EventEmitter } from 'events';
const bus = new EventEmitter();
bus.on('message', (data) => console.log('got:', data));
bus.emit('message', 'hello'); // got: hello
5 个核心方法
ee.on('event', fn) // 订阅
ee.once('event', fn) // 只触发一次后自动取消
ee.off('event', fn) // 取消(等同 removeListener)
ee.emit('event', ...args) // 触发
ee.removeAllListeners('event') // 移除某事件所有监听
ee.listenerCount('event') // 几个监听器
实战:用作模块间通信
// bus.js
import { EventEmitter } from 'events';
export const bus = new EventEmitter();
// auth.js
import { bus } from './bus.js';
bus.emit('user:login', { id: 42, name: 'Alice' });
// analytics.js
import { bus } from './bus.js';
bus.on('user:login', user => {
console.log(`User ${user.name} logged in`);
});
内置 EventEmitter 例子
// HTTP server
server.on('request', (req, res) => { ... });
server.on('connection', socket => { ... });
server.on('error', err => { ... });
server.on('close', () => { ... });
// Stream
readable.on('data', chunk => { ... });
readable.on('end', () => { ... });
readable.on('error', err => { ... });
// Process
process.on('SIGINT', () => { ... });
内存泄漏防护
// 默认警告阈值
ee.getMaxListeners() // 10
// 调高
ee.setMaxListeners(20);
// 或全局调高(一般不用)
require('events').defaultMaxListeners = 20;
⚠ 看到 "MaxListenersExceededWarning" 警告通常是真的 bug——某处反复 .on() 没移除:
// ❌ 每次请求都新加监听
server.on('request', (req, res) => {
db.on('error', () => res.status(500)); // 每个请求加一个,永不移除
});
// ✓ 用 once,或在生命周期结束时移除
server.on('request', (req, res) => {
const handler = () => res.status(500);
db.once('error', handler);
res.on('close', () => db.off('error', handler));
});
error 事件特殊
ee.emit('error', new Error('boom')); // 没监听 → **进程崩**
所有 EventEmitter 都该监听 error:
ee.on('error', err => console.error(err));
once 返回 Promise
import { once } from 'events';
// 老式
ee.once('ready', () => start());
// 新式(async/await 友好)
await once(ee, 'ready');
start();
取消所有监听
ee.removeAllListeners(); // 所有事件所有监听
ee.removeAllListeners('event'); // 仅某事件
自定义类继承
class MyApp extends EventEmitter {
start() {
this.emit('start');
}
}
const app = new MyApp();
app.on('start', () => console.log('started'));
app.start();
同步触发
emit 是同步的——所有监听器在 emit 同一栈里跑:
ee.on('e', () => console.log('1'));
ee.on('e', () => console.log('2'));
console.log('before');
ee.emit('e');
console.log('after');
// 输出:before 1 2 after
如果监听器抛错 → emit 调用方收到。
异步触发:
import { setImmediate } from 'timers/promises';
ee.on('e', async () => {
await setImmediate(); // 放到下个 tick
console.log('async');
});
现代替代
很多场景用 Promise / async iterator 替代 EventEmitter:
// ❌ EventEmitter 风格
ee.on('data', chunk => process(chunk));
ee.on('end', () => done());
// ✓ Async iterator(如果可用)
for await (const chunk of stream) {
process(chunk);
}
坑
- emit
error没监听 → 进程崩 .on()不配对.off()→ 内存泄漏- 监听器太多 → MaxListeners 警告
- emit 是同步的——监听器拖时间会阻塞调用方
下一篇:http 模块。