发布订阅模式通常又被称为消息机制,它定义了对象间的一种一对多的依赖关系,只要当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新,解决了主体对象与观察者之间功能的耦合,即一个对象状态改变给其他对象通知的问题,常用于组件间通信。
js是监听HistoryRouter的变化
class Dep { // 订阅池
constructor(name){
this.id = new Date() //这里简单的运用时间戳做订阅池的ID
this.subs = [] //该事件下被订阅对象的集合
}
defined(){ // 添加订阅者
Dep.watch.add(this);
}
notify() { //通知订阅者有变化
this.subs.forEach((e, i) => {
if(typeof e.update === 'function'){
try {
e.update.apply(e) //触发订阅者更新函数
} catch(err){
console.warr(err)
}
}
})
}
}
Dep.watch = null;
class Watch {
constructor(name, fn){
this.name = name; //订阅消息的名称
this.id = new Date(); //这里简单的运用时间戳做订阅者的ID
this.callBack = fn; //订阅消息发送改变时->订阅者执行的回调函数
}
add(dep) { //将订阅者放入dep订阅池
dep.subs.push(this);
}
update() { //将订阅者更新方法
var cb = this.callBack; //赋值为了不改变函数内调用的this
cb(this.name);
}
}
手写发布订阅
- 需要有一个
map
对象缓存订阅事件 - 订阅(
on
)如果存在事件就往list里面缓存事件 - 取消订阅(
off
)从list对象找到订阅事件删除 - 发布(
emit
)从list对象找到事件去执行就OK - 只发布一次(
once
)执行完删除即可
class EventEmitter{
constructor() {
this.map = {}
}
// 订阅
on(type, handler) {
this.map[type] = (this.map[type] || []).concat(handler)
}
// 取消订阅
off(type, handler) {
if(this.map[type]) {
if(!this.map[type].length) {
delete this.map[type]
} else {
let index = this.map[type].indexOf(handler)
this.map[type].splice(index, 1)
}
}
}
// 发布
emit(type, data) {
this.map[type] && this.map[type].forEach(handler => handler(data))
}
// 执行一次
once(type, handler) {
let fn = (...args) => {
handler.apply(this, args);
this.off(type, handler);
};
this.on(type, fn);
}
}
// 测试
let eventEmitter= new EventEmitter()
eventEmitter.on('click', data => {
console.log(data)
})
eventEmitter.fire('click', {a: 3})//{ a: 3}
eventEmitter.off('click')//销毁后,无结果
eventEmitter.fire('click', {b: 2})//无返回
eventEmitter.once('click', data => {
console.log(data);
})
观察者模式
发布订阅模式除了有发布者和订阅者,还有中间商;
而类似的 观察者模式 只有观察者和消费者:
let observer_ids=0;
let observed_ids=0;
//观察者类
class Observer {
constructor() {
this.id = observer_ids++;
}
//观测到变化后的处理
update(ob){
console.log("观察者" + this.id + `-检测到被观察者${ob.id}变化`);
}
}
//被观察者列
class Observed {
constructor() {
this.observers = [];
this.id=observed_ids++;
}
//添加观察者
addObserver(observer) {
this.observers.push(observer);
}
//删除观察者
removeObserver(observer) {
this.observers = this.observers.filter(o => {
return o.id != observer.id;
});
}
//通知所有的观察者
notify(ob) {
this.observers.forEach(observer => {
observer.update(ob);
});
}
}
let mObserved=new Observed();
let mObserver1=new Observer();
let mObserver2=new Observer();
mObserved.addObserver(mObserver1);
mObserved.addObserver(mObserver2);
mObserved.notify();