自己实现一个简单的事件系统

事件系统

nodejs的事件模块

nodejs官方api文档

  • nodejs中的事件模块,是用来给其他对象提供绑定事件,触发事件等能力。
  • 官方的一个小demo,可以看出,将一个宿主对象集成 events 模块提供的对象,那么这个宿主对象拥有了这个方法。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    const EventEmitter = require('events');

    class MyEmitter extends EventEmitter {}

    const myEmitter = new MyEmitter();
    myEmitter.on('event', () => {
    console.log('an event occurred!');
    });
    myEmitter.emit('event');
  • 我们再看一个官网上的一段代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    const myEmitter = new MyEmitter();
    myEmitter.on('event', function(a, b) {
    console.log(a, b, this);
    // Prints:
    // a b MyEmitter {
    // domain: null,
    // _events: { event: [Function] },
    // _eventsCount: 1,
    // _maxListeners: undefined }
    });
    myEmitter.emit('event', 'a', 'b');

可以看出,其中MyEmitter对象通过该on 添加了一个事件,其中的内部属性也打印出来,这里不难得到启发,可知,事件系统有自己的属性,通过属性联系绑定和取消等函数。

事件系统模块设计

  • 从nodejs的事件系统中,一个事件系统,必须具备的是:

    • 添加绑定事件
    • 取消绑定事件
    • 触发绑定事件
  • 我们整理下思路:

    • 首先我们需要实现一个事件类,用来创建不同的事件对象。如click事件对象,error事件对象。
    • 其次,我们需要为每一个事件对象提供处理函数。

(这里需要明白的是,同一个类型的只有一个事件对象,不同的事件对象有多个处理函数,重复的处理函数是无效的)

事件对象

1
2
3
4
5
6
7
8
9
// 事件对象
/*
*parme:事件名称
*handlerLister:存放该事件的事件处理函数
*/
var EventMeta = function (eventname){
this.name = eventname;
this.handlerList = [];
}

事件宿主对象函数

  • 每一个事件宿主对象都应该持有一个map,用来保存自己的事件单元对象, 那么这个宿主函数的原型架构为:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function createEvents(){
// 存放该事件系统的事件类型
this.EventHandlerMap = [];

// 事件处理函数
var eventSystem={
on:on,
off:off,
trigger:trigger
}

其他辅助函数
// 获取事件系统的事件类型数组。
getEventHandlerMap:getEventHandlerMap;
return eventSystem;
}

```
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
### 整体代码和demo

function createEvents(){
// 存放该事件系统的事件类型
this.EventHandlerMap = [];
// 事件对象
/*
*parme:事件名称
*handlerLister:存放该事件的事件处理函数
*/
var EventMeta = function (eventname){
this.name = eventname;
this.handlerList = [];
}
// 判断函数是否相等
var eqfn = function(fna,fnb){
return fna.toString() == fnb.toString();
}
// 事件处理函数
var eventSystem = {
// 绑定事件函数
on:function(eventname,handler){
var eventMaps = getEventHandlerMap();
var meta = eventMaps[eventname];
if ( !meta ) {
meta = eventMaps[eventname] = new EventMeta(eventname);
meta.handlerList.push(handler);
}else{
var len = meta.handlerList.length;
for (var i = 0; i < len; i++) {
if ( eqfn( handler,meta.handlerList[i] ) ) {
return;
}
}
meta.handlerList.push(handler);
}
},
//取消绑定事件函数
off:function(eventname,handler){
var eventMaps = getEventHandlerMap();
var meta = eventMaps[eventname];
if ( !meta ) {
return false;
}else if(!handler){
eventMaps[eventname] = null;
}else{
var len = meta.handlerList.length;
for (var i = 0; i < len; i++) {
if ( eqfn( handler,meta.handlerList[i] ) ) {
meta.handlerList.splice(i,1);
}
}
}
},
//触发绑定事件函数
trigger:function(eventname){
var eventMaps = getEventHandlerMap();
var meta = eventMaps[eventname];
if ( !meta ) {
console.log("noerror")
return false;
}else{
var len = meta.handlerList.length;
for (var i = 0; i < len; i++) {
meta.handlerList[i].apply(this);
}
}
}
}
// 获取事件类型列表
var getEventHandlerMap = function(){
return this.EventHandlerMap;
}
return eventSystem;
}

var listen = createEvents();
listen.on("error",function(){
console.log("error1")
})
listen.on("error",function(){
console.log("error2")
})
listen.trigger("error")
listen.off("error",function(){
console.log("error2")
})
listen.trigger("error")
var a = createEvents();
a.trigger("error")

资料参考:
自己实现一个简单的事件系统