javascript发布订阅事件封装

151 阅读1分钟

发布订阅是很常见的一种设计模式,接下来就是写一下发布/订阅事件模型

分为三个部分,订阅事件(subscribe),发布事件(publish),取消事件(cancelSub) 举一个客户点外卖的例子,客户点外卖触发了publish事件,而商家和骑手就需要用subscribe订阅客户的事件 先定义一个大的对象:

const PubSub = {
    id:0,  //用于事件的id识别
    callbacks :{ 
    }
}

这个数据结构最后会变成:

image.png

订阅事件代码:

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)