一、 什么是发布-订阅模式
1. 定义
发布-订阅模式其实是一种对象间一对多的依赖关系,当一个对象的状态发送改变时,所有依赖于它的对象都将得到状态改变的通知。
订阅者(Subscriber)把自己想订阅的事件注册(Subscribe)到调度中心(Event Channel),当发布者(Publisher)发布该事件(Publish Event)到调度中心,也就是该事件触发时,由调度中心统一调度(Fire Event)订阅者注册到调度中心的处理代码。
2. 例子
比如我们很喜欢看某个公众号号的文章,但是我们不知道什么时候发布新文章,要不定时的去翻阅;这时候,我们可以关注该公众号,当有文章推送时,会有消息及时通知我们文章更新了。
上面一个看似简单的操作,其实是一个典型的发布订阅模式,公众号属于发布者,用户属于订阅者;用户将订阅公众号的事件注册到调度中心,公众号作为发布者,当有新文章发布时,公众号发布该事件到调度中心,调度中心会及时发消息告知用户。
二、 如何实现发布-订阅模式?
- 创建一个对象
- 在该对象上创建一个缓存列表(调度中心)
- on 方法用来把函数 fn 都加到缓存列表中(订阅者注册事件到调度中心)
- emit 方法取到 arguments 里第一个当做 event,根据 event 值去执行对应缓存列表中的函数(发布者发布事件到调度中心,调度中心处理代码)
- off 方法可以根据 event 值取消订阅(取消订阅)
class Event { constructor() { //创建一个对象 在该对象上创建一个缓存列表(调度中心) this.list = {} } on(event, fn) { //on 方法用来把函数 fn 都加到缓存列表中(订阅者注册事件到调度中心) (this.list[event] || (this.list[event] = [])).push(fn) return this; } emit() { //emit 方法取到 arguments 里第一个当做 event, //根据 event 值去执行对应缓存列表中的函数(发布者发布事件到调度中心,调度中心处理代码) let event = [].shift.call(arguments); if (this.list[event]) { this.list[event].forEach(event => { event.apply(this, arguments) }); } else { throw 'There is no such event' return; } } off(event, fn) { //off 方法可以根据 event 值取消订阅(取消订阅) if (!this.list[event]) return false; if (!fn) { this.list[event] && (this.list[event].length = 0); } else { let index = this.list[event].findIndex(v => v === fn) this.list[event].splice(index, 1) } } } function u1(params) { console.log(1, params) } function u2(params) { console.log(2, params) } let bus = new Event() bus.on('ready', u1) bus.on('ready', u2) bus.off('ready', u2) bus.emit('ready', '123')