一、理解
比如我们很喜欢看某个公众号号的文章,但是我们不知道什么时候发布新文章,要不定时的去翻阅;这时候,我们可以关注该公众号,当有文章推送时,会有消息及时通知我们文章更新了。
公众号属于发布者,用户属于订阅者;用户将订阅公众号的事件注册到调度中心,公众号作为发布者,当有新文章发布时,公众号发布该事件到调度中心,调度中心会及时发消息告知用户。
发布-订阅模式其实是一种对象间一对多的依赖关系,当一个对象的状态发送改变时,所有依赖于它的对象都将得到状态改变的通知。
订阅者(Subscriber)把自己想订阅的事件 注册(Subscribe)到调度中心(Event Channel);
当发布者(Publisher)发布该事件(Publish Event)到调度中心,也就是该事件触发时,由 调度中心 统一调度(Fire Event)订阅者注册到调度中心的处理代码。
二、手写
实现思路:
创建一个类 Observer
在这个类里创建一个缓存列表(调度中心)
on 方法 - 用来把函数fn添加到缓存列表(订阅者注册事件到调度中心)
emit 方法 - 取到event事件类型,根据event值去执行对应缓存列表中的函数(发布者发布事件到调度中心,调度中心处理代码)
off 方法 - 可以根据event事件类型取消订阅(取消订阅)
核心有四:
缓存列表 message
向消息队列添加内容 $on
删除消息队列里的内容 $off
触发消息队列里的内容 $emit
class Observer {
constructor() {
this.message = {} // 消息队列
}
/**
* `$on` 向消息队列添加内容
* @param {*} type 事件名 (事件类型)
* @param {*} callback 回调函数
*/
$on(type, callback) {
// 判断有没有这个属性(事件类型)
if (!this.message[type]) {
// 如果没有这个属性,就初始化一个空的数组
this.message[type] = [];
}
// 如果有这个属性,就往他的后面push一个新的callback
this.message[type].push(callback);
}
/**
* $off 删除消息队列里的内容
* @param {*} type 事件名 (事件类型)
* @param {*} callback 回调函数
*/
$off(type, callback) {
// 判断是否有订阅,即消息队列里是否有type这个类型的事件,没有的话就直接return
if (!this.message[type]) return;
// 判断是否有callback这个参数
if (!callback) {
// 如果没有callback,就删掉整个事件
this.message[type] = undefined;
return;
}
// 如果有callback,就仅仅删掉callback这个消息(过滤掉这个消息方法)
this.message[type] = this.message[type].filter((item) => item !== callback);
}
/**
* $emit 触发消息队列里的内容
* @param {*} type 事件名 (事件类型)
*/
$emit(type) {
// 判断是否有订阅
if(!this.message[type]) return;
// 如果有订阅,就对这个`type`事件做一个轮询 (for循环)
this.message[type].forEach(item => {
// 挨个执行每一个消息的回调函数callback
item()
});
}
}