简单的来说,就是将引用数据对象的对象作为订阅者,存放在数据对象的订阅者队列中或指定的缓存位置,当数据对象发生变化时,通过遍历订阅者队列通知订阅者数据的变化。
这种模式的存在解决了一些场景:例如需要轮询是否发生变化,这对性能无疑是一种浪费(但轮询可以做到主动索取,能避免通知失败的情况)
由于是以推送的形式去通知订阅者,所以该模式可以广泛应用于异步编程中,是一种回调函数的代替方案。该模式也能解耦发布者和订阅者,彼此不需要关注对方有何更改。
DOM事件的绑定就是发布订阅的实现,发布者为DOM,订阅者为listener。
当实现发布订阅模式时,需要关注如下三点
- 指定发布者
- 维护一个订阅者集合,收集、删除等操作
- 发布时遍历集合通知订阅者,或执行订阅者的回调
实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| let publisher = {};
publisher.subscribeList = [];
publisher.addSubscribe = function(fn){ this.subscribeList.push(fn); };
publisher.notify = function(){ this.subscribeList.forEach(function(fn){ fn.apply(this, arguments); },this) };
publisher.addSubscribe(function(){ console.log('first subscriber',this) });
publisher.addSubscribe(function(){ console.log('first subscriber') });
publisher.notify();
|
为了能够更好的区分订阅者订阅的消息种类(那部分数据发生了变化),在添加订阅者队列时可以指定key值标识
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| publisher.subscribeList = {}; publisher.addSubscribe = function(key, fn){ if(!this.subscribeList[key]){ this.subscribeList[key] = []; } this.subscribeList.push(fn); }
publisher.notify = function(...args){ const [key, ...params] = [...ages]; const fns = this.subscribeList[key]; if(!fns){ return false; } fns.forEach(function(){ fn.apply(this, params); }) }
|