1.发布/订阅模式
- 订阅者
- 发布者
- 信号中心
假定,存在一个"信号中心",某个任务执行完成,就向信号中心"发布"(publish)一个信号,其他任务可以向信号中心"订阅"(subscribe)这个信号,从而知道什么时候自己可以开始执行。这就叫做"发布/订阅模式"(publish-subscribe pattern)
个人理解,就是,订阅者是学生家长 , 老师是发布者,公布学生成绩, 班级就是对应每个学生的 信号中心
具体可以看代码
1 <!DOCTYPE html>
2 <html lang="cn">
3 <head>
4 <meta charset="UTF-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 <title>发布订阅模式</title>
7 </head>
8 <body>
9 <script>
10 // 事件触发器
11 class EventEmitter {
12 constructor () {
13 // { 'click': [fn1, fn2], 'change': [fn] }
14 //传null,创建的是没有原型的空对象,提升性能
15 this.subs = Object.create(null)
16 }
17
18 // 注册事件
19 $on (eventType, handler) {
20 this.subs[eventType] = this.subs[eventType] || []
21 this.subs[eventType].push(handler)
22 }
23
24 // 触发事件
25 $emit (eventType) {
26 if (this.subs[eventType]) {
27 this.subs[eventType].forEach(handler => {
28 handler()
29 })
30 }
31 }
32 }
33
34 // 测试
35 let em = new EventEmitter()
36 em.$on('click', () => {
37 console.log('click1')
38 })
39 em.$on('click', () => {
40 console.log('click2')
41 })
42
43 em.$emit('click')
44 </script>
45 </body>
46 </html>
2.观察者模式
- 观察者(订阅者) -- Watcher
update():当事件发生时,具体要做的事情
- 目标(发布者) -- Dep
subs 数组:存储所有的观察者
addSub():添加观察者
notify():当事件发生,调用所有观察者的 update() 方法
- 没有事件中心
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 <title>观察者模式</title>
7 </head>
8 <body>
9 <script>
10 // 发布者-目标
11 class Dep {
12 constructor () {
13 // 记录所有的订阅者
14 this.subs = []
15 }
16 // 添加订阅者
17 addSub (sub) {
18 if (sub && sub.update) {
19 this.subs.push(sub)
20 }
21 }
22 // 发布通知
23 notify () {
24 this.subs.forEach(sub => {
25 sub.update()
26 })
27 }
28 }
29 // 订阅者-观察者
30 class Watcher {
31 update () {
32 console.log('update')
33 }
34 }
35
36 // 测试
37 let dep = new Dep()
38 let watcher = new Watcher()
39
40 dep.addSub(watcher)
41
42 dep.notify()
43 </script>
44 </body>
45 </html>
总结:
- 观察者模式是由具体目标调度,比如当事件触发,Dep 就会去调用观察者的方法,所以观察者模式的订阅者与发布者之间是存在依赖的。
- 发布/订阅模式由统一调度中心调用,因此发布者和订阅者不需要知道对方的存在。