发布订阅模式
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>发布订阅模式</title>
</head>
<body>
<script>
/*
包子铺:
记录; 有谁要预定了我的包子
有人喜欢吃肉的,素的
事件: 当我的包子出炉了,
通知: 这些人来拿包子了
*/
let event = {
clientList:{
},
listen:function (key, fn) {
// key 用户要什么信息,fn 是当信息有了,我们要做些什么
if (!this.clientList[key]) {
this.clientList[key] = [];
}
this.clientList[key].push(fn);
// 当有人需要信息的时候,我们把它加入到订阅列表
},
trigger: function () {
// 假设 有信息来了, 就在这个参数里面
let key = Array.prototype.shift.call(arguments);
let fns = this.clientList[key];
if (!fns || fns.length === 0) {
return false;
}
for (let i = 0, fn; fn = fns[i++];) {
console.log(arguments)
fn.apply(this,arguments);
}
}
}
let installEvent = function (obj) {
for (let i in event) {
obj[i] = event[i]
}
}
let salesBaozi = {};
installEvent(salesBaozi);
salesBaozi.listen("肉包子",(count)=>{
console.log("小明,你的包子来了,现在只剩下"+count+"个")
})
salesBaozi.listen("肉包子",(count)=>{
console.log("小王,你的包子来了,现在只剩下"+count+"个")
})
</script>
</body>
</html>
假设:
有1000个人全部关注了这个变化,无论在哪里改变这个值本质上都是set,那么我把trigger激活,在那个数据的访问器的set写上即可,只要值发生变化,向所有监听者发布通知,所有人都能知道接收到并同步数据。
第二种方式
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>发布订阅模式</title>
</head>
<body>
<script>
const eventHub = {
map: {
// click: [f1 , f2]
},
on: (name, fn)=>{
eventHub.map[name] = eventHub.map[name] || []
eventHub.map[name].push(fn)
},
emit: (name, data)=>{
const q = eventHub.map[name]
if(!q) return
q.map(f => f.call(null, data))
return undefined
},
off: (name, fn)=>{
const q = eventHub.map[name]
if(!q){ return }
const index = q.indexOf(fn)
if(index < 0) { return }
q.splice(index, 1)
}
}
eventHub.on('click', console.log)
eventHub.on('click', console.error)
setTimeout(()=>{
eventHub.emit('click', 'xxx')
},3000)
</script>
</body>
</html>
第三种方式
class EventHub {
map = {}
on(name, fn) {
this.map[name] = this.map[name] || []
this.map[name].push(fn)
}
emit(name, data) {
const fnList = this.map[name] || []
fnList.forEach(fn => fn.call(undefined, data))
}
off(name, fn) {
const fnList = this.map[name] || []
const index = fnList.indexOf(fn)
if(index < 0) return
fnList.splice(index, 1)
}
}
// 使用
const e = new EventHub()
e.on('click', (name)=>{
console.log('hi '+ name)
})
e.on('click', (name)=>{
console.log('hello '+ name)
})
setTimeout(()=>{
e.emit('click', 'xxx')
},3000)