如何理解js的发布-订阅模式

发布-订阅模式/观察者模式

发布-订阅模式也叫观察者模式,这是一个一对多的关系,可以多个订阅者订阅同一个事件,当事件触发时就会通知订阅者去执行订阅时绑定的程序;

我举个例子来解释一下:

A同学想在结婚的时候邀请好友B、C、D、E、F、G...来喝喜酒,这个邀请的名单其实就是订阅事件

class Person extends EventEmitter{
    constructor(){
        super();
        
    }
}

let A= new Person();

function drinkFn(){
    console.log( `xxxx年xx月xx日来xx大酒店和我的喜酒!`)
}
A.on("结婚",drinkFn);

等到A同学要结婚的时候,他就会去通知他的好友XXX时间XX酒店过来喝酒,这个过程就是发布事件

A.emit("结婚");

以下是我的实现过程:

class EventEmitter {
    constructor(){
        this._count=null;
        
    }
    //订阅事件
    on(type,callBack,flag){
        //创建_events对象
        if(!this._events){
            this._events=Object.create(null);
        }
        
        // 判断_events对象是否有type属性
        if(this._events[type]){
            if(flag){
                this._events[type].unshift(callBack)
            }else{
                this._events[type].push(callBack)
            }
            
        }else{
            this._events[type]=[callBack]
        }
        
        //type如果不是newListener类型,则执行newListener对应的函数
        if(type!=="newListener"){
            this._events["newListener"]&&this._events["newListener"].forEach(fn=>{
                fn(type,callBack);
            })
        }
        // 超出最大绑定事件限制提示
        if(this._events[type].length>=this.getMaxListeners()){
            console.log("超出最大绑定事件限制")
        }
    }

    //订阅一次性事件
    once(type,callBack,flag){
        function warp(...argments){
            callBack(...argments);
            this.removeListener(type,callBack)
        }
        warp.cb=callBack;
        this.on(type,warp,flag);
        
    }

    //发布事件
    emit(type,...args){
        if(this._events[type]){
            this._events[type].forEach(fn => {
                fn.call(this,...args)
            });
        }
    }

    // 获取当前type事件的数组对象
    listeners(type){
        return this._events[type]||[];
    }

    // 订阅事件并在第一时间触发
    prependListener(type,callBack){
        this.on(type,callBack,true);
    }
    
    // 订阅一次性事件并在第一时间触发
    prependOnceListener(type,callBack){
        this.once(type,callBack,true);
    }
    
    // 获取当前实例所有的事件类型
    eventNames(){
        return Object.keys(this._events)
    }
    
    // 获取当前type事件类型的长度
    listenerCount(type){
        if(this._events[type]){
            return this._events[type].length
        }else{
            return 0
        }
        
    }
    
    // 移除type事件所有的执行函数
    removeListener(type,callBack){
        if(this._events[type]){
            this._events[type]=this._events[type].filter(fn=>{
                return callBack!=fn&&fn.cb!=callBack
            })
        }
    }
    
    // 移除实例上所有的事件
    removeAllListeners(){
        this._events=Object.create(null)
    }

    // 获取当前实例的最大事件绑定限制
    getMaxListeners(){
        return this._count ? this._count :EventEmitter.defaultMaxListeners;
    }
    
    // 设置当前实例的最大事件绑定限制
    setMaxListeners(n){
        this._count=n;
    }
        
}
// 设置默认的最大事件绑定限制
EventEmitter.defaultMaxListeners=10;

module.exports=EventEmitter;
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 对于开发人员来说,设计模式有时候就是一道坎,但是设计模式又非常有用,过了这道坎,它可以让你水平提高一个档次。而在a...
    WANKUN阅读 2,087评论 0 2
  • 1.实例演进 考虑实现如下功能,点击一个按钮后出现一个遮罩层。原始办法:我们只需要实现一个创建遮罩层的函数并将其作...
    love丁酥酥阅读 2,860评论 0 2
  • 本周目标回顾: 1.完成工作模块测试,输出测试报告 2.继续细分工作目标(进行可行性分析) 3.最少3次晨跑 4....
    未灰阅读 1,319评论 3 0
  • 朋友从小是乖乖女,听妈妈的话,上学考试,工作,每一步都会听从妈妈的安排,也终于如愿以偿成为真正的事业编制。进入某宣...
    怡儿话书影阅读 3,499评论 2 2

友情链接更多精彩内容