Dom无关事件,发布订阅模式

基于事件的编程非常强大,因为它能让你的应用架构充分解耦,让功能变得更加内聚且 具有更好的可维护性。事件本质上是和 DOM 无关的,因此你可以很容易开发出一个事 件驱动的库。这种模式称为发布 / 订阅, 比如vue,emit(xxx,{}) 就是发布一个事件,on(xxx,()=>{})订阅事件。事件驱动编程随处可见


发布订阅模式

  • 发布 / 订阅(Pub/Sub)是一种消息模式,它有两个参与者 :发布者和订阅者。发布者向
    某个信道(channel)发布一条消息,订阅者绑定这个信道,当有消息发布至信道时就会
    接收到一个通知。最重要的一点是,发布者和订阅者是完全解耦的,彼此并不知晓对方的存在。两者仅仅共享一个信道名称。
  • 我们可以先想想,通过发布、订阅模式是怎么实现事件驱动?,首先是有一个事件数组来�收集事件,然后订阅者通过on将事件放入数组,emit(发布)触发数组对应的事件。 简单的过程大概这个样子。
  • 当一个对象能事件驱动,具有发布订阅功能,需要具备什么?最直白的讲,就是有‘emit()’和‘on()’方法,能进行发布和订阅。
    上代码:

写一个超级简单,具有发布、订阅功能的对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
var PubSub = {
//订阅
on: function(ev, callback) {
// 创建 _callbacks 对象,除非它已经存在了
var calls = this._callbacks || (this._callbacks = {});
// 针对给定的事件key创建一个数组,除非这个数组已经存在
// 然后将回调函数追加到这个数组中
(this._callbacks[ev] || (this._callbacks[ev] = [])).push(callback);
return this;
},
//发布
emit: function() {
// 将arguments对象转换为真正的数组
var args = Array.prototype.slice.call(arguments, 0);
// 拿出第1个参数,即事件名称
var ev = args.shift();
// 如果不存在_callbacks对象,则返回
// 或者如果不包含给定事件对应的数组
var list, calls, i, l;
if (!(calls = this._callbacks)) return this;
if (!(list = this._callbacks[ev])) return this;
// 触发回调
for (i = 0, l = list.length; i < l; i++)
list[i].apply(this, args);
return this;
}
};
// 使用
// 测试
//订阅事件
PubSub.on("test", function(data){
alert("我擦!发布test事件了?我订阅了。事件抛的数据是:"+data.name); });
//发布事件后,订阅的地方自动触发
PubSub.emit("test", {name: 'sha' });

把上面的代码 扔浏览器控制台 跑一下,可以用的。

总结: 事件驱动,和发布、订阅通过上面一小段代码有个初步了解,大部分js事件驱动库都是用这种思想,当然库肯定不会这么简陋,要做很多处理,比如事件销毁,同一个事件 销毁某一个回调函数。


作者 [@sha Qihe]

2017 年 5月 5日