Node.js入门教程(十六):EventEmitter
一、什么是 EventEmitterNode.js 所有的异步 I/O 操作在完成时都会发送一个事件到事件队列。Node.js 里面的许多对象都会分发事件一个net.Server对象会在每次有新连接时触发一个事件一个fs.readStream对象会在文件被打开的时候触发一个事件。所有这些产生事件的对象都是events.EventEmitter的实例。EventEmitter是 Node.js 中用于创建、注册和触发事件的核心模块。EventEmitter 是事件驱动编程的基础可以帮助开发者轻松实现事件的发布与订阅机制。二、EventEmitter 类events模块只提供了一个对象events.EventEmitter。EventEmitter 的核心就是事件触发与事件监听器功能的封装。你可以通过require(events)来访问该模块// 引入 events 模块 var events require(events); // 创建 eventEmitter 对象 var eventEmitter new events.EventEmitter();EventEmitter 对象如果在实例化时发生错误会触发error事件。当添加新的监听器时newListener事件会触发当监听器被移除时removeListener事件被触发。三、EventEmitter 的基本用法简单示例// event.js 文件 var EventEmitter require(events).EventEmitter; var event new EventEmitter(); event.on(some_event, function() { console.log(some_event 事件触发); }); setTimeout(function() { event.emit(some_event); }, 1000);运行这段代码1 秒后控制台输出了some_event 事件触发。其原理是event对象注册了事件some_event的一个监听器然后我们通过setTimeout在 1000 毫秒以后向event对象发送事件some_event此时会调用some_event的监听器。执行结果如下$ node event.js some_event 事件触发多个监听器示例EventEmitter 的每个事件由一个事件名和若干个参数组成事件名是一个字符串通常表达一定的语义。对于每个事件EventEmitter 支持若干个事件监听器。当事件触发时注册到这个事件的事件监听器被依次调用事件参数作为回调函数参数传递。// event.js 文件 var events require(events); var emitter new events.EventEmitter(); emitter.on(someEvent, function(arg1, arg2) { console.log(listener1, arg1, arg2); }); emitter.on(someEvent, function(arg1, arg2) { console.log(listener2, arg1, arg2); }); emitter.emit(someEvent, arg1 参数, arg2 参数);执行以上代码运行的结果如下$ node event.js listener1 arg1 参数 arg2 参数 listener2 arg1 参数 arg2 参数以上例子中emitter为事件someEvent注册了两个事件监听器然后触发了someEvent事件。运行结果中可以看到两个事件监听器回调函数被先后调用。这就是 EventEmitter 最简单的用法。四、EventEmitter 方法序号方法 描述1addListener(event, listener)为指定事件添加一个监听器到监听器数组的尾部2on(event, listener)为指定事件注册一个监听器接受一个字符串 event 和一个回调函数3once(event, listener)为指定事件注册一个单次监听器监听器最多只会触发一次触发后立刻解除该监听器4removeListener(event, listener)移除指定事件的某个监听器监听器必须是该事件已经注册过的监听器5removeAllListeners([event])移除所有事件的所有监听器如果指定事件则移除指定事件的所有监听器6setMaxListeners(n)默认情况下EventEmitters 如果你添加的监听器超过 10 个就会输出警告信息该函数用于改变监听器的默认限制数量7listeners(event)返回指定事件的监听器数组8emit(event, [arg1], [arg2], [...])按监听器的顺序执行每个监听器如果事件有注册监听返回 true否则返回 false类方法序号方法 描述1listenerCount(emitter, event)返回指定事件的监听器数量推荐使用emitter.listenerCount(eventName)五、常用示例注册事件监听器const EventEmitter require(events); const myEmitter new EventEmitter(); // 注册一个事件监听器 myEmitter.on(sayHello, (name) { console.log(Hello, ${name}!); }); // 触发事件 myEmitter.emit(sayHello, Alice);输出Hello, Alice!使用 once() 注册一次性事件myEmitter.once(init, () { console.log(Initialization event occurred); }); myEmitter.emit(init); // 打印: Initialization event occurred myEmitter.emit(init); // 不会再触发传递参数给监听器事件触发时可以传递参数供监听器使用myEmitter.on(data, (value1, value2) { console.log(Received values: ${value1}, ${value2}); }); myEmitter.emit(data, Node.js, EventEmitter); // 输出: Received values: Node.js, EventEmittererror 事件如果触发的事件没有对应的监听器EventEmitter 会抛出错误。建议始终为error事件注册监听器myEmitter.on(error, (err) { console.error(Error event triggered:, err); }); myEmitter.emit(error, new Error(Something went wrong)); // 打印: Error event triggered: Error: Something went wrong六、EventEmitter 事件序号事件 描述1newListener该事件在添加新监听器时被触发。参数event事件名称listener处理事件函数2removeListener从指定监听器数组中删除一个监听器时被触发。参数event事件名称listener处理事件函数七、完整实例以下实例通过connection连接事件演示了 EventEmitter 类的应用。创建main.js文件代码如下var events require(events); var eventEmitter new events.EventEmitter(); // 监听器 #1 var listener1 function listener1() { console.log(监听器 listener1 执行。); } // 监听器 #2 var listener2 function listener2() { console.log(监听器 listener2 执行。); } // 绑定 connection 事件处理函数为 listener1 eventEmitter.addListener(connection, listener1); // 绑定 connection 事件处理函数为 listener2 eventEmitter.on(connection, listener2); var eventListeners eventEmitter.listenerCount(connection); console.log(eventListeners 个监听器监听连接事件。); // 处理 connection 事件 eventEmitter.emit(connection); // 移除监绑定的 listener1 函数 eventEmitter.removeListener(connection, listener1); console.log(listener1 不再受监听。); // 触发连接事件 eventEmitter.emit(connection); eventListeners eventEmitter.listenerCount(connection); console.log(eventListeners 个监听器监听连接事件。); console.log(程序执行完毕。);执行结果如下$ node main.js 2 个监听器监听连接事件。 监听器 listener1 执行。 监听器 listener2 执行。 listener1 不再受监听。 监听器 listener2 执行。 1 个监听器监听连接事件。 程序执行完毕。八、error 事件详解EventEmitter 定义了一个特殊的事件error它包含了错误的语义我们在遇到异常的时候通常会触发error事件。当error被触发时EventEmitter 规定如果没有响应的监听器Node.js 会把它当作异常退出程序并输出错误信息。我们一般要为会触发error事件的对象设置监听器避免遇到错误后整个程序崩溃var events require(events); var emitter new events.EventEmitter(); // 如果不注册 error 监听器以下代码会导致程序崩溃 emitter.on(error, function(err) { console.error(捕获到错误:, err); }); emitter.emit(error, new Error(Something went wrong));九、继承 EventEmitter大多数时候我们不会直接使用 EventEmitter而是在对象中继承它。包括fs、net、http在内的只要是支持事件响应的核心模块都是 EventEmitter 的子类。为什么要继承具有某个实体功能的对象实现事件符合语义事件的监听和发生应该是一个对象的方法JavaScript 的对象机制是基于原型的支持部分多重继承继承 EventEmitter 不会打乱对象原有的继承关系自定义类继承 EventEmitterconst EventEmitter require(events); class MyEmitter extends EventEmitter {} const customEmitter new MyEmitter(); customEmitter.on(customEvent, () { console.log(Custom event fired); }); customEmitter.emit(customEvent);大多数 Node.js 核心模块如 HTTP、文件系统都继承了 EventEmitter你可以创建自己的类来继承 EventEmitter。十、本章小结知识点说明EventEmitter 是什么Node.js 事件驱动编程的核心模块实现发布与订阅机制核心方法on()注册监听器emit()触发事件once()一次性监听器移除监听器removeListener()移除指定监听器removeAllListeners()移除所有error 事件特殊事件必须注册监听器否则会导致程序崩溃继承 EventEmitter核心模块都是 EventEmitter 的子类可自定义类继承监听器数量限制默认超过 10 个会警告可用setMaxListeners()调整提示EventEmitter 是 Node.js 事件驱动架构的基石。理解 EventEmitter 是掌握 Node.js 异步编程和事件驱动模式的关键。在实际开发中当需要实现对象间的松耦合通信时EventEmitter 是非常有用的工具。