发布订阅模式
大家都知道,javascript本身就是事件驱动的语言,在日常的dom事件处理中,我们已经习惯了监听一个dom绑定一个事件,然后通过某些动作去触发这个事件,从而来达到想要的效果。事实上,我们非常熟悉这么一个模式,只不过可能不是很清楚这个模式的名字,其实这个模式就是发布订阅模式(又名观察者模式)
目标效果
我们想实现一个事件类,一共有三个方法:subscribe、unsubscribe、publish
subscribe方法用于订阅一个事件
unsubscribe方法用于取消一个已经订阅的事件
publish方法用于发布一个事件
实现思路
首先我们创建这么一个Event类,它有上面的那三个方法:
function Event() {
this.subscribe = function() {}
this.unsubscribe = function() {}
this.publish = function() {}
}
然后我们需要一个对象,来对不同的事件和回调函数进行存储。我们可以把事件名作为这个对象里面的key, 事件的相关属性作为value;我们还需要一个id属性,给订阅的事件分配一个唯一的id,方便后续的一些操作:
function Event() {
var map = {}
var id = 0
// ...
}
下面我们来实现这个subscribe方法。
在我们平时的dom操作中,订阅事件一般会接收两个参数:事件名和事件的处理回调,那么这里我们也接收这两个参数;然后我们的subscribe方法应该把传入的参数保存到我们的map对象中,进行存储。
// ...
this.subscribe = function(name, handler) {
if(!map.hasOwnProperty(name) || !Array.isArray(map[name])) {
map[name] = [];
}
var event = {
id: id++,
name: name,
handler: handler
}
map[name].push(event)
return event // 返回这个对象 方便那我们后续取消订阅
}
// ...
接下来就是发布事件,我们传入事件名,然后publish方法将为我们执行对应的事件处理函数
this.publish = function() {
var name = [].shift.call(arguments) // 传入的第一个参数为事件名 后续所有参数都将传入事件处理器中
if(!map.hasOwnProperty(name) || !Array.isArray(map[name])) {
console.log('event not found')
return
}
for(var i = 0; i < map[name].length; i++) {
var item = map[name][i]
item.handler && item.handler.apply(null, arguments)
}
}
现在我们可以测试一下这两个方法运行是不是正常:
var event = new Event();
event.subscribe('test_event', function(data) {
console.log(data) // this is a text event info
})
event.publish('test_event', 'this is a text event info')
最后就是如何去取消我们的订阅了。在之前subscribe中,我们返回了一个对象,来表示绑定的事件,那么我们可以利用这个返回的对象,来取消这个订阅:
this.ubsubscribe = function(event) {
if(!map.hasOwnProperty(event.name) || !Array.isArray(map[event.name])) {
return
}
map[event.name] = map[event.name].filter(function(item) {
return item.id !== event.id
})
}
下面我测试一下这个方法:
var event = new Event();
var event1 = event.subscribe('test_event', function(data) {
console.log('event1: ' + data)
})
var event2 = event.subscribe('test_event', function(data) {
console.log('event2: ' + data)
})
event.publish('test_event', 'this is a text event info')
// 打印两条数据
// event1: this is a text event info
// event2: this is a text event info
event.ubsubscribe(event1)
event.publish('test_event', 'this is a text event info')
// 只打印一条数据 说明我们的event1取消成功
// event2: this is a text event info
这样我们整个Event类就写完了~
结束
发布订阅模式是javascript事件的基础,是每个前端都应该了解的一种设计模式,这里我只是非常浅显简单的实现了一个发布订阅模式,希望对大家有所帮助~
原文地址:http://blog.yuantang.site/2017/08/19/简单实现一个事件模型