Node.js 词条目录
前端Wiki/Node.js/进阶/事件 events

自定义事件实战

实际开发中不会直接 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;把“发生什么”与“怎么处理”解耦。