当前位置: 代码迷 >> 综合 >> 实现一个 EventEmitter
  详细解决方案

实现一个 EventEmitter

热度:98   发布时间:2023-12-14 06:00:37.0

实现一个 EventEmitter

Node.js的events 模块对外提供了一个 EventEmitter 对象,用于对 Node.js 中的事件进行统一管理。因为 Node.js 采用了事件驱动机制,而 EventEmitter 就是 Node.js 实现事件驱动的基础。在 EventEmitter 的基础上,Node.js 中几乎所有的模块都继承了这个类,以实现异步事件驱动架构。

基本使用
let events = require('events');let eventEmitter = new events.EventEmitter();eventEmitter.on('say',function(name){
    console.log('Hello',name);
})eventEmitter.emit('say','Jonh');

以上代码中,新定义的eventEmitter 是接收 events.EventEmitter 模块 new 之后返回的一个实例,eventEmitter 的 emit 方法,发出 say 事件,通过 eventEmitter 的 on 方法监听,从而执行相应的函数。

常用的 EventEmitter 模块的 API

在这里插入图片描述

实现EventEmitter

那么结合上面介绍的内容,我们一起来实现一个基础版本的EventEmitter,包含基础的one、 off、emit、once、allOff 这几个方法。

class EventEmitter {
    constructor() {
    // 用来存放自定义事件,以及自定义事件的回调函数this.events = {
    }}on(eventName, listener, once = false) {
    if (!eventName || !listener) return// 判断listener是否为函数if (typeof listener !== 'function') {
    throw new TypeError('listener must be a function')}let listeners = (this.events[eventName] = this.events[eventName] || [])// 防止注册同一个事件名的重复的listenerif (listeners.indexOf(listener) === -1) {
    // 为每一个添加的listener添加一个是否只执行一次的标识符 oncelistener.once = oncelisteners.push(listener)}return this}emit(eventName, ...args) {
    let listeners = this.events[eventName]if (!listeners) returnfor (let i = 0; i < listeners.length; i++) {
    const listener = listeners[i]listener.apply(this, args)// 如果只需要执行一次需要特殊处理,执行完成之后,将改监听器移除即可if (listener.once) {
    this.off(eventName, listener)}}return this}off(eventName, listener) {
    let listeners = this.events[eventName]if (!listeners) returnlet index = -1for (let i = 0; i < listeners.length; i++) {
    if (listeners[i] === listener) {
    index = ibreak}}if (index !== -1) {
    listeners.splice(index, 1)}return this}
}

再看下 once 方法和 allOff的实现

	// 直接调用 on 方法,once 参数传入 true,待执行之后进行 once 处理once(eventName, listener) {
    return this.on(eventName, listener, true)}allOff(eventName) {
    if (eventName && this.events[eventName]) {
    this.events[eventName] = []} else {
    this.events = {
    }}}

从上面的代码中可以看到,once 方法的本质还是调用 on 方法,只不过传入的参数区分和非一次执行的情况。当再次触发 emit 方法的时候,once 绑定的执行一次之后再进行解绑。

这样,alloff 方法也很好理解了,其实就是对内部的 events 对象进行清空,清空之后如果再次触发自定义事件,也就无法触发回调函数了。

EventEmitter设计模式

上面代码已经很明显了就是 发布-订阅模式

另外,观察者模式和发布-订阅模式有些类似的地方,但是在细节方面还是有一些区别的,不要把这两个模式搞混了。发布-订阅模式其实是观察者模式的一种变形,区别在于:发布-订阅模式在观察者模式的基础上,在目标和观察者之间增加了一个调度中心

实际使用场景

Vue中不同组件中的通信,其中一种就是EventBus,它和 EventEmitter 思路类似