js手写一个基于发布-订阅的EventCenter

83 阅读1分钟

订阅者把自己想要订阅的事件注册到调度中心,当发布者发布该事件到调度中心,由调度中心调度订阅者注册到调度中心的处理代码。

实现思路

  1. 创建一个类EventCenter
  2. 定义一个事件处理中心handlers
  3. 实现on方法,把函数添加到事件中心,订阅者把事件都注册到调度中心
  4. emit, 根据事件type去执行对应事件中心的函数=>发布者发布事件到调度中心,调度中心处理代码
  5. 取消订阅off
    
    class EventCenter{
      // 1. 定义一个世界容器,用来装事件数组
     constructor(){
       this.handlers = {};
     }
      //2.添加事件方法,参数:事件名,事件方法
      on(type, handler){
        if(!this.handlers[type]){
          this.handlers[type] = [];
        }
        // 存入事件
        this.handlers[type].push(handler)
      }
      
      //3.触发事件,参数:事件名 事件参数
      emit(type, parmas){
        if(!this.handlers[type]){
         return new Error('事件无效')
        }
        // 触发事件,,执行该事件类型上的所有处理函数
        this.handlers[type].forEach(fn => fn(...parmas)
      }
      
      // 4/移除事件,参数:事件名, 要删除的事件,若无第二个参数,则删除该事件的订阅和发布
      off(type, handler){
        if(!this.handlers[type]){
           return new Error('事件无效')
        }
        if(!handler){
         delete this.handlers[type]
        }else {
        // 找到要删除的事件处理函数
         let index = this.handlers[type].findIndex(el => el === handler)
         if(index === -1){
             return new Error(`该${type}无绑定事件`)
         }
         // 移除事件
         this.handlers[type].splice(index, 1)
         if(this.handlers[type].length === 0){
           delete this.handlers[type]
         }
        }
      }
      
      // 事件的单次订阅once, 需要在回调函数执行后,取消订阅当前事件,所以要对传入的回调包一层,
      once(type, handler){
        const one = (...args) => {
         handler(...args)
         this.off(type, one)
        }
        one.initialCallback = handler
        this.on(type, one)
      }
    }