JavaScript实现EventEmitter

304 阅读2分钟

在 JavaScript 中,EventEmitter 是一个常见的模式,尤其在 Node.js 的事件驱动架构中。以下是一个简化版的 EventEmitter 实现:

class EventEmitter {
  constructor() {
    this.events = {};
  }

  // 注册事件
  on(event, listener) {
    if (!this.events[event]) {
      this.events[event] = [];
    }
    this.events[event].push(listener);
  }

  // 触发事件
  emit(event, ...args) {
    if (this.events[event]) {
      this.events[event].forEach(listener => {
        listener(...args);
      });
    }
  }

  // 移除某个事件的某个监听器
  off(event, listener) {
    if (this.events[event]) {
      this.events[event] = this.events[event].filter(l => l !== listener);
    }
  }

  // 移除某个事件的所有监听器
  removeAllListeners(event) {
    if (this.events[event]) {
      delete this.events[event];
    }
  }

  // 为事件注册一次性监听器
  once(event, listener) {
    const onceWrapper = (...args) => {
      listener(...args);
      this.off(event, onceWrapper);
    };
    this.on(event, onceWrapper);
  }
}

// 使用示例:
const emitter = new EventEmitter();

function responseToEvent(msg) {
  console.log(msg);
}

emitter.on('hello', responseToEvent);
emitter.emit('hello', 'Hello World!');  // 输出: Hello World!

emitter.off('hello', responseToEvent);
emitter.emit('hello', 'Hello again!');  // 无输出

以上是一个简化版的 EventEmitter,它提供了基础的事件监听和触发功能。实际的 Node.js 的 EventEmitter 类会有更多的方法和优化,但上面的示例为你提供了一个核心概念。

Node.js 中的 EventEmitter 是一个核心模块,它为实现对象间的事件驱动架构提供了可能性。通过 EventEmitter,一个对象可以发布(emit)一个事件,同时其他对象可以订阅(listen)这个事件。这种机制在 Node.js 中广泛应用,特别是在处理异步操作时,如读取文件、处理网络请求等。

以下是 EventEmitter 的一些基本概念和使用方法:

创建和使用 EventEmitter

  1. 引入 events 模块

    const EventEmitter = require('events');
    
  2. 创建 EventEmitter 实例

    const emitter = new EventEmitter();
    
  3. 监听事件: 使用 onaddListener 方法订阅一个事件。

    emitter.on('myEvent', (data) => {
      console.log('myEvent was fired:', data);
    });
    
  4. 触发事件: 使用 emit 方法发布一个事件。

    emitter.emit('myEvent', 'This is the event data');
    

其他方法

  • once(eventName, listener):为事件添加一次性的监听器。监听器只会触发一次,然后自动移除。
  • removeListener(eventName, listener):移除指定的监听器。
  • removeAllListeners([eventName]):移除所有的监听器,或移除指定事件的所有监听器。
  • listenerCount(eventName):返回指定事件的监听器数量。
  • listeners(eventName):返回指定事件的监听器数组。

注意事项

  • 为了避免潜在的内存泄漏,当为一个事件添加过多的监听器时,EventEmitter 会打印一个警告。默认的监听器数量限制是 10,但可以使用 emitter.setMaxListeners(n) 调整这个数量。
  • EventEmitter 会按照监听器的注册顺序同步调用所有监听器。因此需要确保监听器不会进行长时间的操作,以避免阻塞整个程序。

示例

const EventEmitter = require('events');
const emitter = new EventEmitter();

// 注册监听器
emitter.on('greet', (message) => {
  console.log(`Received greeting: ${message}`);
});

// 触发事件
emitter.emit('greet', 'Hello, world!'); // 输出: Received greeting: Hello, world!

Node.js 中许多核心模块(如 fs, http, stream 等)都使用了 EventEmitter,使得它成为处理异步任务时的重要工具。