My Little World

订阅发布模式

主要思想

通过逻辑处理函数/对象event,使事件订阅和发布过程忽略事件的具体处理过程
订阅时只需要给到event要订阅的事件A,和响应函数,
发布时给到event事件A被触发和相关参数,即可执行订阅时的响应函数
event 充当中介者的角色,管理事件响应的存储和执行

1.简单实现

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
let event = {
caches:{},
on:function(name,fn){
if(!this.caches[name]){
this.caches[name] = []
}
this.caches[name].push(fn)
},
emit:function(name,...args){
if(!this.caches[name]){return}
for(let i=0;i<this.caches[name].length;i++){
let fn=this.caches[name][i]
fn(args)
}
},
remove:function(name,fn){
if(this.caches[name].length<1){return}
for(let i=0;i<this.caches[name].length;i++){
let fn1=this.caches[name][i]
if(fn === fn1){
this.caches[name].splice(i,1)
}
}
}
}
let fn1 = (val)=>{console.log(val,1)}
let fn2 = (val)=>{console.log(val,2)}
event.on('aaa',fn1)
event.on('aaa',fn2)
event.emit('aaa','fire!')

2.全局事件冲突

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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
var Event = (function(){ 
var global = this,
Event,_default = 'default';
Event = function(){
var _listen,
_trigger,
_remove,
_slice = Array.prototype.slice,
_shift = Array.prototype.shift,
_unshift = Array.prototype.unshift,
namespaceCache = {},
_create,
find,
each = function( ary, fn ){
var ret;
for ( var i = 0, l = ary.length; i < l; i++ ){
var n = ary[i];
ret = fn.call( n, i, n);
}
return ret;
};

_listen = function( key, fn, cache ){
if ( !cache[ key ] ){
cache[ key ] = [];
}
cache[key].push( fn );
};

_remove = function( key, cache ,fn){
if ( cache[ key ] ){
if( fn ){
for( var i = cache[ key ].length; i >= 0; i-- ){
if( cache[ key ][i] === fn ){
cache[ key ].splice( i, 1 );
}
}
}else{
cache[ key ] = [];
}
}
};

_trigger = function(){
var cache = _shift.call(arguments),
key = _shift.call(arguments),
args = arguments,
_self = this,
ret,
stack = cache[ key ];

if ( !stack || !stack.length ){
return;
}

return each( stack, function(){
return this.apply( _self, args );
});
};

_create = function( namespace ){
var namespace = namespace || _default;
var cache = {},
offlineStack = [], // 离线事件
ret = {
listen: function( key, fn, last ){
_listen( key, fn, cache );
if ( offlineStack === null ){
return;
}
if ( last === 'last' ){
offlineStack.length && offlineStack.pop()();
}else{
each( offlineStack, function(){
this();
});
}

offlineStack = null;
},

one: function( key, fn, last ){
_remove( key, cache );
this.listen( key, fn ,last );
},

remove: function( key, fn ){
_remove( key, cache ,fn);
},
trigger: function(){
var fn,
args,
_self = this;

_unshift.call( arguments, cache );
args = arguments;
fn = function(){
return _trigger.apply( _self, args );
};

if ( offlineStack ){
return offlineStack.push( fn );
}
return fn();
}
};
return namespace ?( namespaceCache[ namespace ] ? namespaceCache[ namespace ] : namespaceCache[ namespace ] = ret ): ret;
};

return {
create: _create,
one: function( key,fn, last ){
var event = this.create( );
event.one( key,fn,last );
},
remove: function( key,fn ){
var event = this.create( );
event.remove( key,fn );
},
listen: function( key, fn, last ){
var event = this.create( );
event.listen( key, fn, last );
},
trigger: function(){
var event = this.create( );
event.trigger.apply( this, arguments );
}
};
}();

return Event;

})();