eventEmitter简单实现

由于前不久做某厂的前端笔试题,遇到这道题没能实现出来,于是在此进行总结记录。

EventEmitterNode.js中提供的一个监听器类,类似于前端vue中的eventBus事件总线。

其原理主要是发布订阅者模式。

用订阅杂志进行类比,所有的杂志就是一个大对象: events: {}

  • 意林是其中一款杂志,那么意林就是events对象中的一个属性,值为数组(因为订阅意林杂志的人可以不止一个): events: {'意林': []}

  • 当我订阅意林,那么我就应该收入倒意林数组中,让意林知道我订阅了它: events: {'意林': ['我']} (这里’我’是执行函数)

  • 最后,当意林发布了新一期杂志时,那么我就会收到这一期杂志,也就是意林对数组中的’我’进行了执行

  • 当我觉得意林不好看了,那我就会取消订阅,于是乎在意林数组中将我移除即可

  • 如果我只想看下一期的意林,下下一期的意林我不想看了,那么我就进行单次订阅即可。(使用once方法)

    下面这个EventEmitter类进行了简单实现,主要实现 ‘on’、‘emit’、'once’和’remove’四个方法

class EventEmitter {
  // 初始化事件对象
  constructor() {
    this.events = {}
  }

  // 事件监听,监听的过程就是订阅,也就是把订阅者收集起来
  on(eventName, callback) {
    // 如果不存在该事件,则进行数组初始化
    if (!this.events[eventName]) {
      this.events[eventName] = []
    }
    // 存在对应的数组继续订阅收集,则把事件推入收集数组
    this.events[eventName].push(callback)
    // 返回自身 方便链式调用
    return this
  }

  // 事件触发,触发的过程就是发布,也就是通知订阅者
  emit(eventName, ...args) {
    // 不存在该事件,则不触发
    if (!this.events[eventName]) {
      return this
    }
    // 存在则对收集的订阅者一一通知(函数一一执行)
    const fns = this.events[eventName]
    // 执行的时候绑定自身this
    fns.forEach(fn => fn.apply(this, args))
    // 返回自身 方便链式调用
    return this
  }

  // 解绑事件,取消订阅,将订阅者从订阅者数组中移除
  remove(eventName, callback) {
    if (!this.events[eventName]) {
      return this;
    }
    // 没有指定解绑事件? 就是没有指定对应的订阅者,那么移除所有订阅者
    if (!callback) {
      this.events[eventName] = null
      return this
    }
    // 否则找到该事件, 就是对应的订阅者,将其移除
    const index = this.events[eventName].indexOf(callback);
    this.events[eventName].splice(index, 1);
    return this;
  }

  // 单次绑定事件,执行完后解绑
  once(eventName, callback) {
    const only = () => {
      callback.apply(this, arguments);
      this.remove(eventName, only);
    };
    this.on(eventName, only);
    return this;
  }
}


const emt = new EventEmitter()
// 订阅者1
const listener1 = function (...args) {
  console.log('意林的第一个订阅者', ...args);
}
// 订阅者2
const listener2 = function (...args) {
  console.log('意林的第二个订阅者', ...args);
}
// 收集订阅者,将杂志命名为'yilin'
emt.on('yilin', listener1)
emt.on('yilin', listener2)

// 500ms后订阅者1不想要该杂志了,进行取消订阅
setTimeout(() => {
  emt.remove('yilin', listener1)
}, 500)

// 1秒后意林杂志更新了,进行发布,通知订阅者,这时由于订阅者1取消订阅了,所以订阅者1就不会执行了
setTimeout(() => {
  emt.emit('yilin', 'hello world')
}, 1000)

// 打印结果为:1s后打印 `意林的第二个订阅者 hello world`

以上只是简单实现,如果有不正确的地方,还请各位大佬指正

你可能感兴趣的:(js,前端)