Skip to content

Node.js 事件触发器 (Event Emitter)

Node.js 基于异步、事件驱动的架构运行。这意味着 Node.js 中的许多操作(例如处理网络请求、读取文件或与数据库交互)不会阻塞(block)程序执行。相反,它们在完成或发生重要情况时会触发事件(event)。

实现这一核心概念的是内置 events 模块中的 EventEmitter 类。许多 Node.js 内置对象(如 HTTP 服务器、流(stream)、子进程(child process))都继承自 EventEmitter。

EventEmitter 允许对象触发命名事件(named events),这些事件会导致函数对象(称为“监听器”或“listener”)被调用。

你可以直接使用 EventEmitter 在自己的代码中实现观察者模式(observer pattern)。首先,导入该类:

const EventEmitter = require('events');

然后,创建一个实例:

// 创建一个 eventEmitter 对象
const myEmitter = new EventEmitter();
  • emitter.on(eventName, listener) 或 emitter.addListener(eventName, listener): 为指定的 eventName 注册一个 listener 函数。每当该事件被触发时,此函数就会被调用。同一个事件可以添加多个监听器。
  • emitter.emit(eventName[, ...args]): 触发(emit)指定的 eventName。这会同步地按照注册顺序调用该事件的所有注册监听器,并将提供的 args 参数传递给它们。
  • emitter.once(eventName, listener): 注册一个 listener,它最多为指定的 eventName 调用一次。监听器在被调用后会自动移除。
  • emitter.removeListener(eventName, listener) 或 emitter.off(eventName, listener): 移除指定事件的指定 listener。
  • emitter.removeAllListeners([eventName]): 移除所有监听器,或者仅移除指定 eventName 的监听器。
  • emitter.listenerCount(eventName): 返回当前注册给指定 eventName 的监听器数量。
  • 'newListener' (eventName, listener): 在添加监听器之前触发。
  • 'removeListener' (eventName, listener): 在移除监听器之后触发。
  • 'error' (err): 一个特殊事件。如果一个 EventEmitter 触发了 'error' 事件,但没有为该事件注册任何监听器,Node.js 通常会终止进程并抛出未捕获异常(uncaught exception)。因此,务必在可能触发错误的 EventEmitters 上注册错误监听器。

让我们创建一个简单的示例来演示基本用法(eventDemo.js):

const EventEmitter = require('events');
// 创建一个 emitter 实例
const myEmitter = new EventEmitter();
// 1. 为 'greet' 事件注册一个监听器
const listener1 = (name) => {
console.log(`监听器 1: 你好, ${name}!`);
};
myEmitter.on('greet', listener1);
// 2. 为 'greet' 事件注册另一个监听器
const listener2 = (name) => {
console.log(`监听器 2: 欢迎, ${name}!`);
};
myEmitter.on('greet', listener2);
// 3. 为 'specialGreet' 事件注册一个一次性监听器
myEmitter.once('specialGreet', (message) => {
console.log(`特别问候: ${message}`);
});
// 检查监听器数量
console.log(`'greet' 事件的监听器数量: ${myEmitter.listenerCount('greet')}`); // 输出: 2
console.log(`'specialGreet' 事件的监听器数量: ${myEmitter.listenerCount('specialGreet')}`); // 输出: 1
// 4. 触发 'greet' 事件并带一个参数
console.log("\n触发 'greet' 事件...");
myEmitter.emit('greet', 'Alice');
// listener1 和 listener2 都会被调用
// 5. 触发 'specialGreet' 事件
console.log("\n触发 'specialGreet' 事件...");
myEmitter.emit('specialGreet', '这只发生一次!');
// 监听器将被调用
console.log(`触发后 'specialGreet' 事件的监听器数量: ${myEmitter.listenerCount('specialGreet')}`); // 输出: 0
// 6. 移除 listener1
console.log("\n移除监听器 1...");
myEmitter.removeListener('greet', listener1);
console.log(`移除后 'greet' 事件的监听器数量: ${myEmitter.listenerCount('greet')}`); // 输出: 1
// 7. 再次触发 'greet'
console.log("\n再次触发 'greet' 事件...");
myEmitter.emit('greet', 'Bob');
// 现在只有 listener2 会被调用
// 8. 错误处理
myEmitter.on('error', (err) => {
console.error('--- 发生错误 ---');
console.error(err.message);
});
console.log("\n触发一个 'error' 事件...");
myEmitter.emit('error', new Error('发生了一些错误!'));
// 如果没有注册错误监听器,程序会在这里崩溃。
console.log('\n程序结束.');

运行脚本:

$ node eventDemo.js

预期输出:

Listeners for 'greet': 2
Listeners for 'specialGreet': 1
Emitting 'greet' event...
Listener 1: 你好, Alice!
Listener 2: 欢迎, Alice!
Emitting 'specialGreet' event...
特别问候: 这只发生一次!
Listeners for 'specialGreet' after emit: 0
Removing listener 1...
Listeners for 'greet' after removal: 1
Emitting 'greet' event again...
Listener 2: 欢迎, Bob!
Emitting an 'error' event...
--- 发生错误 ---
发生了一些错误!
程序结束.

此示例展示了如何注册监听器(on, once)、触发事件(emit)、检查监听器数量(listenerCount)、移除监听器(removeListener)以及处理特殊的 'error' 事件。

理解 EventEmitter 对于有效使用 Node.js 核心模块和许多依赖异步、事件驱动模式的第三方库至关重要。