发布订阅模式,又叫做观察者模式,描述对象间的一对多依赖关系。我举几个常见例子以便理解:报纸或杂志发布订阅、js编程中的事件模型、手机流量超限制提醒等等
使用场景
-
应用于异步编程,替代传统回调。
用它的好处是可以切换我们的关注点,关注点集中在订阅事件,而在异步回调中我们需要关注内部运行状态。
-
取代对象之间的硬编码机制,对象之间不必再显式调用。
优点是对象间达到松耦合,缺点是当有多个发布者和订阅者嵌套时,极难debug。
实战例子:
browser 中通过发布订阅模式实现事件机制,可直接执行
let EventP=(() => {
let clientList={}, //订阅回调函数
listen, //监听器
trigger,//触发器
remove;
listen= (key,fn) => {
if(! clientList[key]){
clientList[key]=[];
}
clientList[key].push(fn);
};
trigger= (...rest) => {
let key=rest.shift(),
fns=clientList[key];
if(!fns||fns.length===0){
return false;
}
fns.forEach(function (val,index) {
val.apply(this,rest);
});
}
remove=(key,fn) => {
let fns=clientList[key];
if(!fns){
return false;
}
if(!fn){
fns && (fns.length =0);
}else{
fns.forEach(function (val,index) {
if(val==fn){
fns.splice(index,1);
}
});
}
};
return{
listen:listen,
trigger:trigger,
remove:remove,
}
})();
EventP.listen('console',(info) => {
console.log(info);
})
EventP.trigger('console','hello gcy'); //hello gcy
node当中已内置实现,下面是应用案例
let util= require('util');
let events = require('events');
function PC() {
events.EventEmitter.call(this);
}
// util.inherits //封装了es5的Object.create
util.inherits(PC,events.EventEmitter);
//equivalent writing
// function PC() {
// events.EventEmitter.call(this);
// for(let tmpName in Event.EventEmitter.prototype){
// this[tmpName]=Event.EventEmitter.prototype[tmpName];
// }
// }
let pcInstance=new PC();
/**
* keyInput 可以添加多个listeners
*/
pcInstance.on('keyInput',(track) => {
console.log("track input",track);
});
let inputEnd=() => {
console.log("input End");
}
pcInstance.on('keyInput',inputEnd);
/**
*移除监听,必须有引用
*/
// pcInstance.removeListener('keyInput',inputEnd);
pcInstance.emit('keyInput','hello world gcy');
// ----------------------------------------------------------------------
// 对象组织事件名称,以便维护,模块复用
// let e={
// keyInput:'keyInput',
// charge:'charge'
// ........
// }
//
说明 在node中我认为event的出现是为了解决异步问题(一般是事件驱动型)。event的本质是观察者模式的realize。它是base class之一
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。