-
Notifications
You must be signed in to change notification settings - Fork 22
/
Copy path44_支持先发布再订阅、并提供命名空间的观察者模式.html
146 lines (143 loc) · 5.63 KB
/
44_支持先发布再订阅、并提供命名空间的观察者模式.html
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
134
135
136
137
138
139
140
141
142
143
144
145
146
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<pre>
有时,需要先发布,再订阅。如42中的登录,获取登录信息可能很快,但其他模块可能加载的很慢,就会造成已经发布了登录成功的消息,但其他模块还没有订阅的错误。
所以需要让观察者模式支持先缓存要发布的消息,等到有模块订阅消息的时候再正式发布消息。
另外,Event对象中只存在一个clientList,当订阅多了,就可能出现命名冲突的问题。所以还需要支持创建命名空间。
</pre>
<script>
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;
})();
/************** 先发布后订阅 ********************/
Event.trigger('click', 1);
Event.listen('click', function(a) {
console.log(a); // 输出:1
});
/************** 使用命名空间 ********************/
Event.create('namespace1').listen('click', function(a) {
console.log(a); // 输出:1
});
Event.create('namespace1').trigger('click', 1);
Event.create('namespace2').listen('click', function(a) {
console.log(a); // 输出:2
});
Event.create('namespace2').trigger('click', 2);
</script>
</body>
</html>