什么是发布订阅模式
什么是发布订阅模式我这里不多就不多阐述了,给大家提供几个我觉得讲的比较好的博文,请各位自行阅读
发布-订阅模式解释 这一篇文章应该是一个java coder写的,但是设计模式这种东西并不分语言,各位可以借鉴一下
Javascript中理解发布--订阅模式这一篇是我们前端人写的,但是比较长,大家有耐心可以看看
发布中心实现
我对发布中心的实现,可以不看(看了能够更好的理解发布订阅模式)
//实现发布中心
/*
* log=[{
* index: Number, 日志编号(自增)
* type: String, 日志类型('subscribe','unsubscribe','publish')
* eventName: String, 事件名
* time: new Date(), 时间
* fun:Function 订阅/取订的方法(只有日志类型为'subscribe'或'unsubscribe'的才有)
* param:Object 触发事件时的参数(只有日志类型为'publish'的才有)
* }]
* eventCenter = {
* eventName:[Function,Function] //eventName即为事件名,其值为订阅方法列表
* }
* .subscribe(eventName, fun) 订阅 eventName:事件名 fun:订阅方法
* .unsubscribe(eventName, fun) 取订 eventName:事件名 fun:订阅方法
* .publish(eventName[,param]) 发布 eventName:事件名 param:事件参数
* .showLog([filter]) 日志展示 filter 过滤器,同数组的过滤器用法 返回过滤后的log
* .showEventCenter([eventName]) 事件中心 eventName 事件名 返回事件绑定的方法
* */
let subscribeCenter = function () {
//事件中心
let eventCenter = {};
//日志
let log = [];
//添加日志函数
function pushLog(type, eventName, fun, param) {
let info = {
index: log.length,
type: type,
eventName: eventName,
time: new Date()
};
if (fun) {
info.fun = fun;
}
if (param) {
info.param = param;
}
log.push(info)
}
return {
//订阅
subscribe(eventName, fun) {
pushLog("subscribe", eventName, fun);
eventCenter[eventName] = eventCenter[eventName] || [];
eventCenter[eventName].push(fun);
},
//取消订阅
unsubscribe(eventName, fun) {
pushLog("unsubscribe", eventName, fun);
let onList = eventCenter[eventName];
if (onList) {
for (let i = 0; i < onList.length; i++) {
if (onList[i] === fun) {
onList.splice(i, 1);
return
}
}
}
},
//发布
publish(eventName, param) {
pushLog("publish", eventName, null, param)
let onList = eventCenter[eventName];
if (onList) {
for (let i = 0; i < onList.length; i++) {
onList[i](param)
}
}
},
//显示日志
showLog(filter) {
filter = filter || (() => true);
let returnLog = log.filter(filter);
returnLog.forEach(x => {
let y = {};
for (let key in x) {
y[key] = x[key]
}
return y
});
return returnLog;
},
//显示事件中心
showEventCenter(eventName) {
let selectEM = eventName ? eventCenter[eventName] : eventCenter, returnEM = {};
for (let key in selectEM) {
returnEM[key] = [];
selectEM[key].forEach(x => {
returnEM[key].push(x)
});
}
return returnEM
}
}
}();
如果有看我上一篇文章中事件监听实现的朋友应该对这个不部分代码有一种熟悉的感觉,确实事件监听和发布订阅的实现非常的像。我主要多做的就是一个日志的拓展,保证了每次的动作都可以被监听和查看;
发布中心API
这个在上面是有的,但是因为上面的部分有一些同学是不看的,所以就在这里摘出来,方便这些同学了解发布中心的用法
/*
* log=[{
* index: Number, 日志编号(自增)
* type: String, 日志类型('subscribe','unsubscribe','publish')
* eventName: String, 事件名
* time: new Date(), 时间
* fun:Function 订阅/取订的方法(只有日志类型为'subscribe'或'unsubscribe'的才有)
* param:Object 触发事件时的参数(只有日志类型为'publish'的才有)
* }]
* eventCenter = {
* eventName:[Function,Function] //eventName即为事件名,其值为订阅方法列表
* }
* .subscribe(eventName, fun) 订阅 eventName:事件名 fun:订阅方法
* .unsubscribe(eventName, fun) 取订 eventName:事件名 fun:订阅方法
* .publish(eventName[,param]) 发布 eventName:事件名 param:事件参数
* .showLog([filter]) 日志展示 filter 过滤器,同数组的过滤器用法 返回过滤后的log
* .showEventCenter([eventName]) 事件中心 eventName 事件名 返回事件绑定的方法
* */
发布/订阅模式在异步中的应用
这里是重点,需要大家仔细看,理解了这段代码不光可以解决异步问题,还可以理解发布订阅者模式是如何应用的;
//发布者
let f1 = function () {
setTimeout(function () {
console.log("'done' 事件发布 参数:", 123);
subscribeCenter.publish("done", 123);
console.log("事件中心", subscribeCenter.showEventCenter());
console.log("f3 取订 'done'");
subscribeCenter.unsubscribe("done", f3);
setTimeout(function () {
console.log("'done' 事件发布 参数:", 233);
subscribeCenter.publish("done", 233);
console.log("事件中心", subscribeCenter.showEventCenter());
console.log("日志", subscribeCenter.showLog());
}, 100)
}, 100)
};
//订阅者
let f2 = function (param) {
console.log("f2 is running, param is", param);
};
//订阅者
let f3 = function (param) {
console.log("f3 is running, param is", param)
};
//订阅
console.log("f2 订阅 'done'");
subscribeCenter.subscribe("done", f2);
console.log("f3 订阅 'done'");
subscribeCenter.subscribe("done", f3);
//发布
f1();
先贴运行结果
在这里可以看到,该模式与事件监听模式非常相似,但是所有的发布都通过了同一个发布中心来控制,这样的话可以方便我们追踪整个事件的状态;