「这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战」
简介
发布订阅模式,又叫观察者模式。学过Vue的肯定都听过,今天我们就把它讲彻底。
它定义对象之间的一对多依赖关系,当对象状态发生变化时,所有依赖于它的对象都会得到通知。 面试中50%的几率会遇到coding发布订阅的题。
案例
小红从事房屋售卖工作。小明今天找他买房,结果今天没有可售卖的房子,于是小明要了小红的手机号,每天都会给她打电话询问是否有房源。同时还有小李、范闲、凤年等很多人会给小红打电话,不到一个月小红就要辞职,因为她每天都要接上千个电话。
最后她想了一个办法:把所有用户的手机号收集起来,等有房源的时候,挨个给用户发一条短信就可以了。 下面我们来实现一下
const xiaohong = (function(){
const phoneList = [];
function add(phone) {
phoneList.push(phone)
}
function call() {
phoneList.forEach(item => {
console.log('小红给' + item + '发了通知!')
})
}
return {
add,
call
}
})()
xiaohong.add(12345)
xiaohong.add(67891)
xiaohong.add(24680)
xiaohong.call()
优点:
- 小红不需要每天接大量的电话。
- 小红和客户之间没有强耦合,即使小红更换了手机号,也不会影响用户收到通知。
小红作为发布者,当出现新的订阅者时,发布者不需要做任何改动。发布者自己做出改变时,也不会影响到订阅者。
DOM绑定事件
给一个DOM绑定事件,也是发布订阅的一种使用场景。将事件注册进dom中,并取好名称,当DOM触发同名的事件时,将会执行已注册的事件。
document.body.addEventListener( 'click', function(){
alert(2);
}, false );
document.body.click(); // 模拟用户点击
取消订阅
小明把自己的手机号给小红后,第二天自己的基金亏损严重,没有足够的钱买房子了。于是告诉小红有房源后也不需要通知自己了。于是:小红把call的次数记录下来。当有新的订阅者时,就会把按照记录的发布次数,再次发布给新的订阅者。
const xiaohong = (function(){
let phoneList = [];
...
function del(phone) {
phoneList = phoneList.filter((item) => phone !== item);
}
return {
...
del
}
})()
先发布后订阅
如果先发布,后订阅。那么订阅者还能收到之前发布的信息吗?应该怎样实现这个功能?
const xiaohong = (function(){
let phoneList = [];
let callCount = 0;
function add(phone) {
phoneList.push(phone)
for (let i = 0; i < callCount; i++) {
console.log('小红给' + phone + '发了通知!')
}
}
function call() {
phoneList.forEach(item => {
console.log('小红给' + item + '发了通知!')
})
callCount++
}
return {
add,
call
}
})()
xiaohong.call()
xiaohong.call()
xiaohong.call()
xiaohong.add(12345)
面试遇到怎么写
上面的例子写的都比较简单,面试的时候肯定要写的更完善,我们就写一个完整版的例子:
- 事件订阅$on;
- 事件派发$emit;
- 取消订阅$off;
- 先发布后订阅;
const eventBus = (function (){
const data = {};
const emitobj = {};
function $on(key, fn) {
data[key] = fn;
if (emitobj[key]) {
data[key]();
delete emitobj[key];
}
}
function $emit(key, ...args) {
if (data[key]) {
data[key](...args)
} else {
emitobj[key] = true;
}
}
function $off(key) {
delete data[key];
}
return {
$on,
$emit,
$off,
}
})()
想要更好可以把data[key]、emitobj[key]改进为数组,这样同一个key可以派发多个事件。
总结
满足事件发布订阅的三要素:
- 首先要指定好谁充当发布者(比如售楼处);
- 然后给发布者添加一个缓存列表,用于存放回调函数以便通知订阅者(售楼处的花名册);
- 最后发布消息的时候,发布者会遍历这个缓存列表,依次触发里面存放的订阅者回调函数(遍历花名册,挨个发短信)。