大多数的Node核心API的构建使用异步事件的驱动架构,理解Node中的events事件模块就很重要了。

Node.js 里面的许多对象都会分发事件:一个 net.Server 对象会在每次有新连接时触发一个事件, 一个 fs.readStream 对象会在文件被打开的时候触发一个事件。 所有这些产生事件的对象都是 events.EventEmitter 的实例。

一、EventEmitter类

EventEmitter类的是有模块evnets定义的,EventEmitter 的核心就是事件触发与事件监听器功能的封装

  1. const EventEmitter = require('events')
  2. const EventEmitter = require('events')
  3. let eventEmitter = new EventEmitter()
  4. eventEmitter.on('test', () => {
  5. console.log('触发test')
  6. })
  7. eventEmitter.emit('test')

在node环境下运行上述代码最终运行的结果是: ‘触发test’ ,其实这就是一个简单的发布/订阅模式, 通过on来监听一个事件(订阅),通过emit来触发执行(发布)

二、依次触发

EventEmitter 的每个事件由一个事件名和若干个参数组成,事件名是一个字符串,通常表达一定的语义。
对于每个事件,EventEmitter 支持 若干个事件监听器。

  1. const EventEmitter = require('events')
  2. let eventEmitter = new EventEmitter()
  3. eventEmitter.on('someEvent', function(arg1, arg2) {
  4. console.log('listener1', arg1, arg2);
  5. });
  6. eventEmitter.on('someEvent', function(arg1, arg2) {
  7. console.log('listener2', arg1, arg2);
  8. });
  9. // 触发
  10. eventEmitter.emit('someEvent', 'arg1 参数', 'arg2 参数');

image.png

这里注册了两个事件监听器,当执行emit触发的时候,会依次的执行事件监听器中的回调函数

三、移除监听

在事件中还提供了一个off(evnetName, listener)的api,用来移除事件的监听,这个api还有一个别名removeListener()

  1. const EventEmitter = require('events')
  2. let eventEmitter = new EventEmitter()
  3. const callbackA = () => {
  4. console.log('触发test, 执行callbackA')
  5. }
  6. const callbackB = () => {
  7. console.log('触发test, 执行callbackB')
  8. }
  9. eventEmitter.on('test', callbackA)
  10. eventEmitter.on('test', callbackB)
  11. eventEmitter.off('test', callbackA)
  12. eventEmitter.emit('test')

执行结果如下:
image.png

四、once

emitter.once(eventName,listener)也是一个比较重要的api,它表示仅仅只触发一次。

  1. const EventEmitter = require('events')
  2. const eventEmitter = new EventEmitter()
  3. const callback = () => {
  4. console.log('触发test')
  5. }
  6. eventEmitter.once('test', callback)
  7. // 第一次触发
  8. eventEmitter.emit('test')
  9. // 第二次触发
  10. eventEmitter.emit('test')

执行结果
image.png

这里我们会发现虽然手动触发了两次事件,但是实际上仅仅之触发了一次callback的回调。once执行的实际过程是在callback函数我们会去移除事件监听器,下面我们使用on来模拟once的过程

  1. const EventEmitter = require('events')
  2. const eventEmitter = new EventEmitter()
  3. const callback = () => {
  4. console.log('触发test')
  5. eventEmitter.off('test', callback)
  6. }
  7. eventEmitter.on('test', callback)
  8. // 第一次触发
  9. eventEmitter.emit('test')
  10. // 第二次触发
  11. eventEmitter.emit('test')

我们对上面的程序稍加改造就可以实现一个和once一样的效果

五、继承 EventEmitter

大多时候时候我们并不会直接使用EventEmitter, 而是把其当做一个基础类,在其他的模块中去继承它。包括 fs、net、 http 在内的,只要是支持事件响应的核心模块都是 EventEmitter 的子类。

为什么要这样做呢?原因有两点:
首先,具有某个实体功能的对象实现事件符合语义, 事件的监听和发生应该是一个对象的方法。
其次 JavaScript 的对象机制是基于原型的,支持 部分多重继承,继承 EventEmitter 不会打乱对象原有的继承关系。

参考资料

node 官方文档:http://nodejs.cn/api/events.html#events_emitter_removelistener_eventname_listener
node 菜鸟教程: https://www.runoob.com/nodejs/nodejs-event.html