准备工作 — 了解发布订阅和观察者模式
最后更新于:2022-04-02 08:11:54
>[success] 发布订阅 和 观察者
[参看关于发布订阅 和观察者我在其他专栏的总结链接](https://www.kancloud.cn/cyyspring/more/1351742)
>[info] ## 发布订阅
~~~
1.发布订阅模式的构成三部分,'订阅者'、'发布者'、'信号中心'
2.假定 存在一个'信号中心',某个任务执行完成,就向信号中心'发布'(publish)一个信号,
其他任务可以向信号中心'订阅'(subscribe)这个信号,从而知道什么时候自己可以开始执行。
这就叫做'发布/订阅模式'(publish-subscribe pattern)
3.简单的理解'信号中心' 其实有两个核心功能'注册事件','触发事件'。订阅者通过在信号中心'注册事件',
发布者通过发布信号触发信号中心的'触发事件'。让订阅者接收到触发信息
~~~
>[danger] ##### vue 中对发布订阅的应用
~~~
1.vue中自定义事件就是利用了'发布订阅模式'
// 订阅中心
const vm = new Vue({})
// 注册事件
vm.$on('dataChage', (msg) => {
console.log(msg) // 测试数据
})
// 触发事件
vm.$emit('dataChage', '测试数据')
2.下面案例把调用信号中心注册事件的叫'订阅者',使用信号中心触发事件叫'发布者'
// eventBus.js
// 事件中心
let eventHub = new Vue()
// ComponentA.vue
// 发布者
addTodu: function () {
// 发布消息(事件) 触发事件
eventHub.$emit('add-todo', { text: this.newTodoText })
this.newTodoText = ''
}
// ComponentB.vue
// 订阅者
created: function () {
// 注册事件
eventHub.$on('add-todo', this.addTodo)
}
~~~
>[danger] ##### 模拟 Vue 自定义事件的实现
~~~
// 事件中心
class EventEmitter {
constructor() {
// { 'click': [fn1, fn2], 'change': [fn] } 键为事件名称 值为存储事件处理函数的数组
this.subs = Object.create(null)
}
// 注册事件,需要事件名和事件方法因此需要两个参数
$on(eventType, handler) {
this.subs[eventType] = this.subs[eventType] || []
this.subs[eventType].push(handler)
}
// 触发事件,触发事件是在注册事件中标记的
// 因此第一个参数触发事件名 第二个参数是传递的参数
$emit(eventType, ...params) {
this.subs[eventType] && this.subs[eventType].forEach(handler => {
handler(...params)
})
}
}
let em = new EventEmitter()
em.$on('click', (val) => {
console.log('click1', val)
})
em.$on('click', (val) => {
console.log('click2', val)
})
em.$emit('click', '测试')
// 打印结果
click1 测试
click2 测试
~~~
>[info] ## 观察者
~~~
1.观察者(订阅者) - Watcher
1.1.update(): 当事件发生时,具体要做的事情
2.目标(发布者) - Dep 知道观察者的存在
2.1.subs 数组: 存储所有的观察者
2.2.addSub(): 添加观察者
2.3.notify(): 当事件发生,调用所有观察者的 update() 方法
3.观察者和发布订阅的最大区别'没有事件中心',观察者模式是通过发布者进行进行记录观察者和调用观察者
~~~
>[danger] ##### 观察者例子代码
~~~
// 发布者
class Dep {
constructor() {
this.subs = []
}
// 记录观察者
addSub(sub) {
if (sub && sub.update) {
this.subs.push(sub)
}
}
// 发布通知
notify() {
this.subs.forEach(sub => {
sub.update()
})
}
}
// 观察者具备updata 方法
// 订阅者-观察者
class Watcher {
update() {
console.log('update')
}
}
// 测试
let dep = new Dep()
let watcher = new Watcher()
dep.addSub(watcher)
dep.notify()
~~~
>[info] ## 二者的区别
~~~
1.观察者模式是由具体目标调度,比如当事件触发,Dep就会去调用观察者方法,
所以观察者模式的订阅者与发布者之间存在依赖关系
2.发布/订阅模式由统一调度中心调用,因此发布者和订阅者不需要知道对方存在,
隔离两者且减少两者之间的关系
3.通过发布订阅 和 观察者 中二者对订阅者的存储结构来看,发布定订阅由于大家共享一个事件中心
因此为了区分每个订阅者想要订阅的类型因此采用的是对象形式'{evnet:[....],evnet2:[....]}'
观察者只是为自己的那一类订阅者服务因此他的形式是数组'[]' 简单的说,发布定订阅是所有订阅者的集合
并且利用key 进行分类,而观察者是一类订阅者,如果这类订阅者不是此类观察者,需要创建新的观察
者对这类订阅者进行订阅 和 发布
~~~
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/9f/03/9f0310c07da325e64a690b42326b19d6_768x546.png)
';