Skip to content

发布订阅模式

1. 什么是发布订阅模式?

发布订阅模式是⼀种消息范式,消息发送者(发布者)不会将消息直接发送给特定的接受者(订阅者),⽽是将发布的消息分为不同 的类别,通过⼀个中间的消息代理来调度消息,发布者⽆需了解有哪些订阅者存在。同样的,订阅者也只接受⾃⼰感兴趣的那⼀类消息,⽆ 需了解发布者是否存在。 发布者和订阅者都不知道彼此的存在,是完全的松耦合。

自己理解一下就是: 发布-订阅模式其实是一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到状态改变的通知。

image.png

2. 发布订阅模式可以解决什么问题?

作用其实就是将发布者和订阅者解耦了(代码解耦),在实际开发中,经常会遇到某个方法内处理很多的逻辑,最简单的就是直接在方法内直接写。这种是高度耦合的面向过程的写法。对于代码维护不友好。

而发布-订阅模式就是将两者分离。我触发了某个事件(这里我们将触发该方法定义为事件),我只向调度中心通知,我并不知道调度中心内会怎么处理,有多少个人响应。我只管通知。 而订阅者只管在调度中心订阅,有人调用它才响应。

例如: vue中的自定义事件,on,$emit

缺点:创建订阅者要消耗一定的事件和内存。过度使用,会导致程序难以跟踪维护。

3. 发布订阅模式里面的概念

有三个角色,订阅者消息调度中心发布者

若把发布订阅想成一个杂志的发布订阅,则可以这么理解三者的关系:

  • 订阅者:相当于用户,我在中心订阅了这分杂志;
  • 消息调度中心:杂志社;
  • 发布者:相当与某个杂志负责人,他来中心这注册一个的杂志;

4. 实现发布订阅

4.1 思路

_events:调度中心 on 订阅: 方法用来把函数都存放在调度中心(订阅这事件注册到调度中心) emit 发布:方法取到arguments里第一个当做event,根据event值去执行调度中心的事件(发布者发布事件到调度中心,调度中心开始处理代码) off 解绑: 方法可以根据event值取消订阅(取消订阅) once 触发一次:方法只监听一次,调用完毕后删除缓存函数(订阅一次)

4.2 代码实现

js
class PubSub {
    _events = {} // 事件中心

    // 订阅
    on(event,callback){
        if(!this._events) {
            this._events = {};
        };

        if(this._events[event]) {
            this._events[event].push(callback)
        }else {
            this._events[event] = [callback]
        }
    }

    // 发布
    emit(event,...arg){
        if(this._events && this._events[event]) {
            this._events[event].forEach(cb=>{
                cb(...arg)
            })
        }
    }

    // 解绑 cb指的是可以单独解绑某个事件
    off(event,cb) {
        if(this._events&& this._events[event]) {
            this._events[event] = this._events[event].filter(item=> (item!== cb && item.fn !== cb))
        }
    }

    // 只会触发一次
    once(event,callback) {
        let one = (...arg)=>{
            callback(...arg) // 先发布
            this.off(event) // 再解绑 这里因为emit里面发布的是one函数,所以解绑也得解绑one
        }
        // 为了解绑成功,需要将传进来的回调函数也存起来
        one.fn = callback;
        this.on(event,one)
    }
}

module.exports = PubSub