聊聊node中的event模块

185 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天,点击查看活动详情

event模块是node中核心模块之一,大部分的核心API都依赖event模块进行异步执行。它通常是作为一种基类,被其他模块继承的。
例如http模块接收post数据或者是错误捕捉:

const http = require('http');

const server = http.createServer((req, res) => {
  let buf = Buffer.from([]);
  req.on('data', (chunk) => {
    buf = Buffer.concat([buf, chunk]);
  });

  req.on('end', () => {
    console.log(buf.toString());
  });
});

event模块在node中几乎无处不在,所以他在node中非常重要。那么现在就来了解一下node中的event吧~

工作原理

与普通的发布订阅模式相同,event对象中有两种概念:监听器触发器
监听器的作用就是给event新增一个监听事件,当触发器触发对应事件时调用已经声明的监听器。 而触发器是用于触发对应事件的。
所以,event模块的工作原理如下图:

image.png

模块构成

event模块包含EventEmitter类,还有一些全局event的方法

1.EventEmitter类

EventEmitter是一个提供事件监听与触发事件的类。
实例化时接收一个参数captureRejections,表示是否接受自动promise的reject

const { EventEmitter } = require('events');

const myEvent = new EventEmitter({
    // 是否接受自动promise的`reject`
    captureRejections: true
})

当我们创建一个新的EventEmitter实例对象后,我们就可以在event对象中新增监听器与触发监听器

  • addListener & on 方法,用于向event对象中添加一个监听器,一个event对象可以添加多个同名的监听器,当触发时会依次触发添加的监听器。一般来说,监听器的数量是有限制的,默认为10,当然也可以通过设置改变监听器的最大数量。
const { EventEmitter } = require('events');

const myEvent = new EventEmitter();

myEvent.on('event', () => {
  console.log('event 1');
});

myEvent.addListener('event', () => {
  console.log('event 2');
});

myEvent.emit('event');

// event 1
// event 2
  • emit 用于触发已经添加的监听器。

addListeneremit 是 event 对象中最核心的方法。用于新增与触发监听器。

  • event其他方法
方法名作用
eventNames获取事件中所有监听器的名字 (string| Symbol)[]
getMaxListeners获取添加监听器最大数量
listererCount(eventName)获取对应事件名的监听器数量
listeners(eventName)获取对应事件监听器的副本
removeListener(eventName)删除对应名称的监听器
off同removeListener
once添加只会触发一次的事件监听器
prependListener向监听器数组头部插入新的监听器
prependOnceListener向监听器数组头部插入新的只触发一次的监听器
removeAllListeners([listeners])删除数组中的所有监听器
setMaxListeners设置最大的监听器数量
rawListeners(eventName)返回对应事件的监听器数组的副本

2. event全局方法

event 全局方法用于修改和获取event模块的一些全局配。比如修改和获取最大监听器数量,添加对应event对象的监听器等等...

  • event.on 用于添加指定event事件的监听器

const event = require('events');
const { EventEmitter } = event;

const myEvent = new EventEmitter();

const listener = event.on(myEvent, 'test');

listener.next().then((val) => {
  console.log(val, ' hello');
});

myEvent.emit('test', '123', '456');

// { value: [ '123', '456' ], done: false }  hello

  • setMaxListeners(nums, [...eventEmitter]) 设置对应event对象的最大监听器

const event = require('events');
const { EventEmitter } = event;
const myEvent = new EventEmitter();

event.setMaxListeners(2, myEvent);

myEvent.on('test', (...args) => {
  console.log(args);
});
myEvent.on('test', (...args) => {
  console.log(args);
});
myEvent.on('test', (...args) => {
  console.log(args);
});

myEvent.emit('test', '123', '456');

// warnning

  • 其他event方法
方法名作用
getEventListeners(emitterOrTarget, eventName)返回名为eventName的事件的监听器数组的副本。
defaultMaxListeners直接修改默认最大监听器数量
errorMonitor用于异常捕捉
once(emitter, name)添加一个只执行一次的监听器

模拟实现event模块

了解了event的api与工作原理,下面就来实践一下:编写一个异步的处理的方法,并新增一个在event当处理完成后进行触发事件。

const event = require('events');

const myEvent = new event.EventEmitter();

class ComplexEvent {
  constructor() {
    this.event = myEvent;
  }
  handleCall = function () {
    // do something...
    this.event.emit('call');
  };

  handleEvent = function () {
    return new Promise((resolve) => {
      // do something...
      this.event.emit('data', 123);
      setTimeout(() => {
        resolve();
        this.event.emit('end');
      }, 1000);
    });
  };

  handleEnd = function () {
    // do something...
    this.event.emit('end');
  };
}

const complexEvent = new ComplexEvent();

complexEvent.event.on('call', () => {
  console.log('on call');
});

complexEvent.event.on('data', (data) => {
  console.log('on data', data);
});

complexEvent.event.on('end', () => {
  console.log('on end');
});

complexEvent.handleCall();
complexEvent.handleEvent();

// on call
// on data 123
// on end

总结

  1. event是一个用于异步执行触发事件的模块,是一个很标准的发布—订阅设计模式
  2. event通常用于基类的继承
  3. eventEmitter类,event方法介绍
  4. event模块实战

参考

  1. event

  2. lib/event.js