发布订阅模式的javascript实现
👉👉本文共850字📘
读完共需3分钟⌚
¶发布订阅模式
在软件架构中,发布-订阅是一种消息范式,消息的发送者(称为发布者)不会将消息直接发送给特定的接收者(称为订阅者)。而是将发布的消息分为不同的类别,无需了解哪些订阅者(如果有的话)可能存在。同样的,订阅者可以表达对一个或多个类别的兴趣,只接收感兴趣的消息,无需了解哪些发布者(如果有的话)存在。
发布/订阅是消息队列范式的兄弟,通常是更大的面向消息中间件系统的一部分。大多数消息系统在API中同时支持消息队列模型和发布/订阅模型,例如Java消息服务(JMS)。
这种模式提供了更大的网络可扩展性和更动态的网络拓扑,同时也降低了对发布者和发布数据的结构修改的灵活性。
优点:
¶JavaScript里的发布订阅模式
在dom事件里面,有一种事件监听的模式就是基于发布订阅设计的,比如非常常见的给节点添加点击事件
var button = document.getElementById("button")
button.addEventListener('click',() => {alert('click')},false)
这样的写法好处很明显,分离事件触发和事件内容解耦。
在node里面,还有EventEmitter这个类,用来实现发布订阅模式,来处理不同对象之间的事件调用。
const EventEmitter = require('events');
const MyEventEmitter extends EventEmitter
const myEventEmitter = new MyEventEmitter
myEventEmitter.on('event',() => {
console.log("target this event")
})
myEventEmitter.emit("event")
// target this event
我之前用BackBone构建单页面应用的时候,就广泛用到了发布订阅模式处理不同组件之间的数据交互,但是这种方法如果滥用,会造成事件交互逻辑的不清晰,所以,父子组件数据交互还是推荐用回调的方式来做。
¶怎么实现eventEmitter
下面是简单实现eventEmitter的JavaScript代码
function EventEmitter() {
this._event = {}
this.maxListenerNum = 10
}
EventEmitter.prototype.on = function(type,callback) {
if(typeof callback !== "function") {
throw new TypeError('callback must be a function')
}
if(!this._event) {
this._event = Object.create(null) // 这里判断不存在就生成一个,如果是继承的,不会继承这个 _event
}
if(this._event[type] ) {
if(this._event[type.length > this.maxListenerNum] ) {
throw new Error("too long")
}
this._event[type].push(callback)
} else {
this._event[type] = [callback]
}
}
EventEmitter.prototype.once = function (type,callback) {
let warp = (...args) => {
callback(...args)
this.removeListener(type,warp)
}
warp.flag = callback
this.on(type,warp)
}
EventEmitter.prototype.removeListener = function(type,callback) {
if(this._event[type] ) {
this._event[type].splice(this._event[type].indexOf(callback),1)
}
}
EventEmitter.prototype.removeListeners = function(type){
this._event[type] = null
}
EventEmitter.prototype.emit = function(type,...args) {
if(this._event[type]) {
this._event[type].forEach(fn => {
fn(...args)
});
}
}
测试代码
var my = new EventEmitter
my.on('a',(a) => {
console.log(a);
})
my.once('once', (a) => {
console.log(a);
})
let add = (a,b) => {
console.log(a+b);
}
my.on('b',add)
my.emit('a',1)
my.emit('a',2)
my.emit('b',1,2)
my.emit('once',1)
my.emit('once',2)
my.removeListeners('a')
my.emit('a',1)
my.removeListener('b')
my.emit('b',1,2)
/* 输出
1
2
3
1
*/
参考:
1.https://zh.wikipedia.org/zh-hans/%E5%8F%91%E5%B8%83/%E8%AE%A2%E9%98%85