订阅发布模式定义了一种一对多的依赖关系,让多个订阅者对象同时监听某一个主题对象。这个主题对象在自身状态变化时,会通知所有订阅者对象,使它们能够自动更新自己的状态。
将一个系统分割成一系列相互协作的类有一个很不好的副作用,那就是需要维护相应对象间的一致性,这样会给维护、扩展和重用都带来不便。当一个对象的改变需要同时改变其他对象,而且它不知道具体有多少对象需要改变时,就可以使用订阅发布模式了。
一个抽象模型有两个方面,其中一方面依赖于另一方面,这时订阅发布模式可以将这两者封装在独立的对象中,使它们各自独立地改变和复用。订阅发布模式所做的工作其实就是在解耦合。让耦合的双方都依赖于抽象,而不是依赖于具体,从而使得各自的变化都不会影响另一边的变化。
记得redux是为什么而出现的吗?
就是针对复杂的数据状态的管理,当一个状态发生了变化,你可能要在多个地方更新这些变化,同时这些状态的变化,又会引起其他的状态的变化。
而订阅发布就是解决这样的问题存在的。
有时候,你想监听一种状态,当在某种情况下,触发它,然后做一些相应的事,有点儿类似我们的自定义事件。订阅发布,也是解决这一类问题的利器。
基本的原理是维护一个对象,每次对这个对象进行遍历和更新。
function PubSub() {
this.handles = {
eventName: {
eventsList: [],
isOne: false,
}
}
}
PubSub.prototype.subscribe = function (eventName, callback) {
let EventsList = [];
if (arguments.length < 2) {
throw new TypeError('arguments error');
}
if (Reflect.has(this.handles, eventName)) {
EventsList = this.handles[eventName].eventsList;
} else {
this.handles[eventName] = {
eventsList: [callback],
isOne: false,
};
}
EventsList.push(callback);
}
PubSub.prototype.notify = function (eventName, ...rest) {
if (this.handles[eventName]) {
let EventsList = this.handles[eventName].eventsList, i = 0, isOne = this.handles[eventName].isOne;
if (EventsList) {
for (; i < EventsList.length; i++) {
EventsList[i].apply(this, rest)
}
}
if (isOne) {
this.unsubscribe(eventName)
}
}
return this;
}
const myPub = new PubSub();
myPub.subscribe('event', function (data) {
console.log('触发');
console.log(data)
})
document.getElementById('btn').onclick = function () {
myPub.notify('event', 123);
}
我在npm发布了关于订阅发布的模块。基本使用如下所示。
import PubSub from 'wd-pub-sub';
// 绑定一个事件名为event的自定义事件
PubSub.subscribe('event', function (data) {
console.log('触发');
console.log(data);
});
// 触发事件名为event的自定义事件
PubSub.notify('event', 123);
基本的API如下:
subscribe(eventName, callback);
发布一个自定义的事件
unsubscribe(eventName, callback);
接触一个自定义的事件
subscribeOne(eventName, callback);
发布一个只触发一次的自定义事件
notify(eventName, callback);
触发已经发布的自定义事件