发布订阅是很常见的一种设计模式,接下来就是写一下发布/订阅事件模型
分为三个部分,订阅事件(subscribe),发布事件(publish),取消事件(cancelSub) 举一个客户点外卖的例子,客户点外卖触发了publish事件,而商家和骑手就需要用subscribe订阅客户的事件 先定义一个大的对象:
const PubSub = {
id:0, //用于事件的id识别
callbacks :{
}
}
这个数据结构最后会变成:
订阅事件代码:
PubSub.subscribe = function(type,fn){
let token = 'token_'+(this.id++)
//如果订阅的事件存在了
if(this.callbacks[type]){
this.callbacks[type][token]=fn
}else{
//如果不存在
this.callbacks[type] = {
[token]:fn
}
}
return token
}
发布事件代码:
PubSub.publish = function (type,data){
if(!this.callbacks[type]) return
let types = this.callbacks[type]
Object.values(types).forEach((callback)=>{
callback(data)
})
}
取消事件:
////取消订阅
/*
** str 为空清空所有订阅事件 str可以是事件名和id
*/
PubSub.cancelSub = function(str){
if(str===undefined){
this.callbacks = {}
}else if(typeof str==='string'){
//str可以是事件名和id
if(str.indexOf('token_')===0){
//这里只会返回同一个订阅事件下的所以token子事件
let callbackObj = Object.values(this.callbacks).find((obj)=>obj.hasOwnProperty(str))
console.log('callbackObj',callbackObj)
delete callbackObj[str]
}else{
delete this.callbacks[str]
}
}
}
find里面的代码解析
// //例如: Object.values(this.callbacks)就是:
// buy:{
// token_0:fn,
// token_1:fn
// },
// gohome:{
// token_2:fn
// }
// //但是加了find过滤就是包含这个token的兄弟节点也一起出来
// {
// token_0:fn,
// token_1:fn
// }
key名和不关事的其他事件就不出现了
实例调用:
let pid0 = PubSub.subscribe('buy',data=>{
console.log(`我是商家,收到了你的订单,内容是${data}`)
})
PubSub.subscribe('buy',data=>{
console.log(`我是外卖小哥,收到了你的订单,内容是${data}`)
})
PubSub.subscribe('gohome',data=>{
console.log(`我回家了内容是${data}`)
})
PubSub.publish('buy',{
title:'毛家饭店',
content:'白饭一碗',
price:100,
address:'我家'
})
PubSub.publish('gohome',{
title:'回家'
})
//取消订阅
// PubSub.cancelSub()
// PubSub.cancelSub('buy')
PubSub.cancelSub(pid0)
console.log("PubSub",PubSub)