自定义事件实战
实际开发中不会直接 new EventEmitter,而是写一个类继承它,把自己的关键动作封装成事件:比如一个“任务队列”在入队、完成、出错时 emit 事件,外部代码只管 on 监听,互相解耦。
典型场景:HTTP 服务器把“请求到达”做成事件(res.on)、构建工具把“文件变动”做成事件(gulp/webpack 插件)、自定义日志器按级别发事件。学会 EventEmitter,就读懂了 Node 生态一半的设计模式。
- 继承 EventEmitter 让自定义类具备事件能力
- 事件先注册后触发(构造函数里 emit 可能还没人监听)
- 同步性:emit 会阻塞当前代码直到所有监听器执行完
JS
const { EventEmitter } = require('events'); // 自定义任务队列:把内部状态变化通知给外部 class TaskQueue extends EventEmitter { constructor() { super(); this.pending = []; this.done = 0; } push(task) { this.pending.push(task); this.emit('enqueue', task); // 对外广播:入队了 return this; } async run() { while (this.pending.length) { const task = this.pending.shift(); try { await task(); this.done++; this.emit('success', this.done); } catch (e) { this.emit('error', e); // 错误也广播出去 } } this.emit('drain'); // 全部清空 } } // 使用方:只关心事件,不关心队列内部 const q = new TaskQueue(); q.on('enqueue', t => console.log('入队一个任务')); q.on('success', n => console.log('已完成', n, '个')); q.on('error', e => console.error('任务失败:', e.message)); q.on('drain', () => console.log('全部搞定')); q.push(() => new Promise(r => setTimeout(r, 300))); q.push(() => Promise.reject(new Error('网络故障'))); q.run();
本节要点自定义事件 = 继承 EventEmitter + 在关键动作处 emit;把“发生什么”与“怎么处理”解耦。




