发布订阅模式

265 阅读1分钟

概述

发布订阅模式,主要围绕一个事件池来实现,在事件池中添加事件类型和对应的函数,这样在触发事件时就可以调用所有的方法了

代码实现

(function(){
//每个实例都有一个池子
    class Sub{
        costructor(){
            this.pond={}
        }
        //向事件池中添加方法
        $on(type,func){
        //检测对象事件池中是否有该type如果美有添加并赋值[]
            this.pond[type]?null:this.pond[type]=[]
            let arr=this.pond[type]     //拿到type的数组
            //判断数组中用没有相同的方法,如果有就不添加
            arr.includes(func)?null:arr.push(func)
            
        }
        //从事件池中移除方法
        $off(type,func){
           let typeArr= this.pond[type]
           if(!typeArr)return;
          this.pond[type]=typeArr.filter(item=>{
            return item!==func
          })
        }
        $emit(type,...args){
            let typeArr=this.pond[type]
            if(!typeArr)return
            for(let i;i<typeArr.length;i++){
                if(typeArr[i]==null){
                    typeArr.splice(i,1)
                    i--
                    continue
                }
                typeArr[i](...args)
            }
        }
    }
    return function subscribe(){
        return new Sub
    }
})()

总结

每一个事件池都是Sub类的实例,实例中的bond属性就是池子,本身是个对象,对象中存放各个类型对应的函数,类中设置公共方法on向池子中添加函数,off移除函数,$emit调用相应type值所用方法

数组塌陷问题

当调用$emit执行所用函数时如果有函数是操作删除(splice)正在遍历执行的数组时,会造成数组塌陷(删除元素后面的元素前移,造成一些函数不会执行)

解决

在操作时把要删除的数组元素设为null(用null占位),在$emit函数中,对设置为null的位置删除并把i-- 或者执行的函数每次都是经过深拷贝原数组得来的,这样在执行所有函数,有的函数删除当前数组元素时,循环执行的数组不变,