跳到主要内容

发布订阅模式

什么是发布—订阅模式

又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知。在JavaScript开发中,我们一般用事件模型来替代传统的发布—订阅模式。

应用场景:

100个用户喜欢小四的写的小说,但是小四写小说需要时间,所以这100个人每隔一会就会问一下小四写完没(setInterval),小四卒...

小四的哥哥明姚也喜欢写小说,然后开通了一个微博,这100个用户都关注了(订阅),明姚写完发布一篇微博,用户都会收到(发布),时效性很强,且避免了用户的频繁无用询问

实际上 addEventListener 也算是发布—订阅模式:

//订阅 点击事件
document.addEventListener( 'click', function(){
console.log(1)
}, false )

//发布 模拟点击事件/用户自己点击会发布
document.click() // 模拟用户点击

手动实现发布订阅模式

class Obeserver {
constructor(){
// 定义小说发布如 天龙八部、射雕英雄传
this.callbacks = {}
}
$on(name, fn){
// 监听 订阅某部小说
this.callbacks[name] = this.callbacks[name] || []
this.callbacks[name].push(fn)
}
$emit(name, ...args){
// 触发 发布小说
if(this.callbacks[name]){
this.callbacks[name].forEach(cb=>cb(...args))
}
}
$off(name, cb) {
// 取消订阅
const targetListen = this.callbacks[name]
if (!targetListen) {
// 如果 name 对应的小说没有被人订阅,则直接跳出
return false
}
/* 会有两种情况。A和B都订阅了某一部小说,发布完成A会自己去看,B会通知给她女朋友看,所以要区分回调。 */
if (!cb) {
// 如果没有传入具体的要删除的回调函数,(注意回调函数应该是同一个引用地址,有名函数,作为参数作为$off第二个参数的实参)表示需要取消 name 对应小说的所有订阅
targetListen && (targetListen.length = 0)
} else {
targetListen.forEach((el, idx) => {
if (el === cb) {//两个方法应该是同一个引用地址
/* 因为第一行是引用地址 直接删除也会将目标引用数据更改*/
targetListen.splice(idx, 1) // 删除订阅者的回调函数
}
})
}
}
}

使用

const bus = new Obeserver()
// 等待发工资
bus.$on('fagongzi', function(e) {
console.log('发工资了 %s', e)
})
// 财务打钱5毛
bus.$emit('fagongzi', 0.5)
// 钱太少了,跑路
bus.$off('fagongzi')
// 少发了5毛 再补上 这会已经跑路,所以接收不到通知了
bus.$emit('fagongzi', 0.5)

vue已经实现发布订阅

  mounted() {
//订阅
this.$on('foo', e => {
console.log(e)
})
},
methods: {
//点击发布
handleClick() {
this.$emit('foo', '我完了')
}
}