“乞丐版”发布订阅模式

今天室友问我,你能手写一个发布订阅模式吗?我:???,好像听说过是一个一对多的关系?好吧,我还是太菜了,那今天就先来搞一个简易版发布订阅模式瞅瞅,只实现发布和订阅功能。

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

发布-订阅模式是对象中一种一对多的依赖关系,当一个对象触发触发某一事件时,所有订阅该事件的对象都能得到通知。

举个🌰:假如有一个售楼处需要发布卖房消息,并且将消息发送给客户,首先能收到消息的客户一定是订阅了售房消息的客户,而能收到消息的客户一定是售楼处发布了消息之后才能接收到消息,且售楼处只有一个,客户则是多个,就对应了发布者与订阅者一对多的情况。

1.webp

以此可以看出:

  • 发布者:发布者发布信息(相当于例子中的售楼处)
  • 订阅者:订阅者订阅发布者发布的信息(相当于例子中的客户)

2. 怎样实现发布订阅模式?

我们这个“乞丐版”发布订阅模式只有订阅和发布功能:

  • on(type, fn)订阅事件,其中接收两个参数,type为订阅事件的事件名,fn为事件触发之后执行的回调函数;
  • emit(type,...args) 发布事件,其中接收两个参数,type为发布的事件名,...args为传给订阅回调函数的参数;
简易版

我希望有这样一个类,可以实现发布和订阅功能,代码如下:

class EventEmitter {
    constructor() {
        this.events = new Map(); // 存放订阅事件
    }
    on(type, fn) { // 事件订阅,type 订阅事件的名称, fn 触发的回调函数
        
    }
    emit(type,...args) { // 事件发布,type 发布事件的名称, args 发布事件的额外参数
  
    }
}
实现on()方法

已知on()接收两个参数,type为订阅事件的事件名,fn为事件触发之后执行的回调函数,只有发布事件执行了,才能触发fn,所以fn应该被存起来,放到emit()中执行,代码如下:

on(type, fn) {
        if (!this.events.get(type)) { // 此事件没人订阅过
            this.events.set(type, [fn]); 
        } else {
            this.events.get(type).push(fn) // 同一个事件多人订阅
        }      
    }
实现emit()方法

已知emit()接收两个参数,type为发布的事件名,...args为传给订阅回调函数的参数,其中我们还需要处理一下this的指向问题,每一个订阅事件的回调函数fn可能都不一样,所以需要apply显示绑定一下,代码如下:

 emit(type,...args) {
        const handle = this.events.get(type)  // 先读取到type
        handle.forEach(fn => { // 将handle中的所有事件触发
            fn.apply(this, args)    // fn执行掉
        })
    }
简易版完整代码
class EventEmitter {
    constructor() {
        this.events = new Map();
    }
    on(type, fn) {
        if (!this.events.get(type)) { // 此事件没人订阅过
            this.events.set(type, [fn]); 
        } else {
            this.events.get(type).push(fn) // 同一个事件多人订阅
        }      
    }
    emit(type,...args) {
        const handle = this.events.get(type)  // 先读取到type
        handle.forEach(fn => { // 将handle中的所有事件触发
            fn.apply(this, args)    // fn执行掉
        })
    }
}
测试案例:

不接收参数:

const emits = new EventEmitter()

emits.on('sell', () => { // 订阅事件
    console.log('小明去买房');
})
emits.on('sell', () => { // 订阅事件
    console.log('李华去买房');
})
emits.on('sellcar', () => { // 订阅事件
    console.log('小红去买车位');
})
emits.emit('sell')  // 发布事件

image.png 接收参数:

const emits = new EventEmitter()

emits.on('sell', (e) => { // 订阅事件
    console.log('小明去买房', e);
})
emits.on('sell', (e) => { // 订阅事件
    console.log('李华去买房', e);
})
emits.on('sellcar', (e) => { // 订阅事件
    console.log('小红去买车位', e);
})
emits.emit('sell',100)  // 发布事件

image.png

总结

这真的是简便的不能再简便的一种写法了,如果亲们能接受的话,给个点赞捏~( ̄▽ ̄)~*

全部评论

相关推荐

小红书 后端选手 n*16*1.18+签字费期权
点赞 评论 收藏
分享
伟大的烤冷面被普调:暨大✌🏻就是强
点赞 评论 收藏
分享
11-24 11:23
门头沟学院 C++
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务