前言
在面试场景题中,发布订阅占有举足轻重地地位.发布订阅模式是一种消息通信模式,这一模式,消息的发送者不会将消息直接发送给特定的订阅者.发布者发布信息,如果有订阅者订阅了该消息就会得到这个信息.那么我们手写又是如何实现呢?
正文
组件通信中的发布订阅
我们先从vue中的组件通信中的子传父通信的案例来看.在vue中的字组件我们通过defineEmits来声明一个事件,在父组件中订阅该事件.
vue组件通讯中的发布订阅者,在子组件中负责创建事件并且发布订阅事件,在父组件中负责订阅事件并获取到子组件给到的参数.那么我们接下来如何实现手写呢?
手写发布订阅
class Event {
constructor() {
this.event = {},
this.onceFn = []
}
on(type, fn) {
if (!this.event[type]) {
this.event[type] = []
}
this.event[type].push(fn)
}
emit(type, data) {
this.event[type].forEach((item) => {
item(data)
})
}
off(type, fn) {
this.event[type] = this.event[type].filter((item) => item !== fn)
}
once(type, fn) {
if (this.onceFn.includes(fn)) {
return
}
this.onceFn.push(fn)
this.on(type, fn)
}
}
在上述代码中我们使用类构造函数创建了一个Event函数,在构造函数中我们创建了四个函数on(),emit(),off(),once().且在 constructor()创建了一个对象this.evnet用于存储时间及其对应的处理器列表,数组this.onceFn用于存储只执行一次的函数.那么我们创建的四个函数分别时什么作用呢?
on()是用于订阅事件的.那么这个订阅的思路是如何实现的呢?on()接收两个参数type和fn,其中type表示的是事件类型,fn是事件函数。if (!this.event[type])在对象中如果不存在该属性,this.event[type] = []就添加该属性并把该属性的值设置成一个数组,最后将该事件type的函数存到数组中.这就是on()的作用
emit()发布订阅,接收两个参数type,data这个data是代表函数中的参数,我们使用forEach循环遍历this.evnet[type]数组并执行函数.
off()这是取消订阅事件,它接收参数的意义和on()其实是一模一样的我们使用filter过滤器去除事件类型为type中的某一个函数fn并重新把它赋值给this.event[type].这样的话我们就是实现了取消订阅.
once()也是接收两个参数.但是它的作用是保证同一事件函数值被调用一次,防止被多次调用.首先我们会检查在数组onceFn中是否存在只需要执行一个的函数,如果存在的话,就直接return返回就就不会走下一步.如果存在,就先将该函数添加到数组onceFn中,然后调用on()订阅该事件.
我们来测试订阅
const eventEmitter = new Event();
// 订阅事件
eventEmitter.on('message', (data) => {
console.log('Message:', data);
});
这是我们订阅事件,我们不会有打印结果的,只有发布之后才会有打印eventEmitter.emit('message','xixi')
这里我们先订阅事件然后取消订阅,最后再发布事件
const eventEmitter = new Event();
function Message(data){
console.log(data);
}
// 订阅事件
eventEmitter.on('message',Message);
eventEmitter.off('message',Message);
eventEmitter.emit('message','xixi')
此时我们得到的结果是不会打印内容的。
作者:Virtual09
链接:https://juejin.cn