该模式,广泛地运用于异步实现中。
一、普通的发布、订阅实例
参与者
- 发布者:事件的触发方
-
流程
1、发布者获取用户列表(添加订阅者)
2、发布者触发信息(群发给订阅者) ``` class Man { constructor(key, name) { this.key = key this.name = name }
getMsg(data) { console.log(this.name + ‘get data:’ + data) } }
class Sub { constructor() { this.clientList = [] }
add(user) { let idArr = this.clientList.map(item => item.key) if (!idArr.includes(user.key)) { this.clientList.push(user) } }
notify(data) { this.clientList.forEach(item => { item.getMsg(data) }) } }
let s = new Sub() let m1 = new Man(1, ‘chp’) let m2 = new Man(2, ‘cc’) s.add(m1) s.add(m2)
s.notify(‘股票涨了’)
<a name="BJe9j"></a>
### 二、有中间人的发布、订阅模式
> 模拟 window.addEventListener
<a name="bWo5N"></a>
#### 参与者
- 发布者
- 订阅者
- 中间人
<a name="yAbA9"></a>
#### 流程
看到知乎上一条评论说的好:
- 以前送快递:
> 快递员 -> 用户
- 现在送快递:
> 快递员 -> 菜鸟驿站 -> 用户
class Event { constructor() { this.fnObj = {} }
listen(key, fn) { if (!this.fnObj[key]) { this.fnObj[key] = [] } this.fnObj[key].push(fn) }
trigger(…args) { let key = args[0] let otherArgs = args.slice(1) if (!this.fnObj[key]) { return }
for (let i = 0, fn; fn = this.fnObj[key][i++];) {
fn.apply(this, otherArgs)
}
} }
let event = new Event()
event.listen(‘Dota’, (data) => { console.log(‘正在为您点播Dota内容:’, data) }) // addEventListener是可以添加多个事件的 event.listen(‘Dota’, (data) => { console.log(‘同时还会为您做其他事情’, data) })
event.listen(‘LOL’, (data) => { console.log(‘点播一些LOL的内容’, data) })
event.trigger(‘Dota’, ‘波波卡打野被抓’) ```
三、与Vue
如果我们再仔细想想,Vue的实现,所谓的“数据驱动”,应该也是与发布、订阅模式相关的。
数据改变 -> dom变化,就像有人去通知了一样。