mm_expand 1.8.9 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/eventer.js +747 -80
- package/lib/file.js +57 -48
- package/lib/lang.js +363 -35
- package/lib/timer.js +87 -15
- package/package.json +1 -1
- package/test.js +180 -4
package/lib/eventer.js
CHANGED
|
@@ -1,84 +1,184 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* 事件类
|
|
2
|
+
* 事件类 - 增强版EventBus实现
|
|
3
3
|
*/
|
|
4
4
|
class Eventer {
|
|
5
5
|
/**
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
//
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
6
|
+
* 构造函数
|
|
7
|
+
* @param {Object} config 配置参数
|
|
8
|
+
*/
|
|
9
|
+
constructor(config) {
|
|
10
|
+
this.config = Object.assign({
|
|
11
|
+
max_listeners: 10, // 最大监听器数量
|
|
12
|
+
default_namespace: 'default', // 默认命名空间
|
|
13
|
+
chain_enabled: true // 是否启用链式触发
|
|
14
|
+
}, config || {});
|
|
15
|
+
// 是否为插件
|
|
16
|
+
this.is_plugin = false;
|
|
17
|
+
// 事件字典 - 支持命名空间
|
|
18
|
+
this.dict = {};
|
|
19
|
+
// 事件中间件
|
|
20
|
+
this.middlewares = [];
|
|
21
|
+
// 命名空间映射
|
|
22
|
+
this.namespaces = {};
|
|
23
|
+
// 事件链映射 { 'event1': ['event2', 'event3'], 'namespace:event1': ['event4'] }
|
|
24
|
+
this.eventChains = {};
|
|
25
|
+
// 初始化默认命名空间
|
|
26
|
+
this.namespaces[this.config.default_namespace] = true;
|
|
27
|
+
}
|
|
18
28
|
}
|
|
19
29
|
|
|
20
30
|
/**
|
|
21
|
-
*
|
|
22
|
-
* @param {String} key
|
|
31
|
+
* 监听事件(支持命名空间和优先级)
|
|
32
|
+
* @param {String} key 事件关键字,支持namespace:key格式
|
|
23
33
|
* @param {Object} func 触发函数
|
|
24
34
|
* @param {String} name 增加名称,方便删除,当出现相同名称时会被覆盖
|
|
25
35
|
* @param {Number} times 执行次数 -1为无限次执行
|
|
26
|
-
* @
|
|
36
|
+
* @param {Number} priority 优先级,数字越小优先级越高,默认为0
|
|
37
|
+
* @param {Object} options 其他选项,如throttle、debounce等
|
|
38
|
+
* @param {String} namespace 可选的显式命名空间,优先级高于key中的命名空间
|
|
39
|
+
* @returns {Object} 返回事件信息对象 {namespace, index, name}
|
|
27
40
|
*/
|
|
28
|
-
Eventer.prototype.on = function (key, func, name, times = -1) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
41
|
+
Eventer.prototype.on = function (key, func, name, times = -1, priority = 0, options = {}, explicitNamespace = null) {
|
|
42
|
+
// 解析命名空间
|
|
43
|
+
var parsed = this._parseKey(key);
|
|
44
|
+
var namespace = explicitNamespace || parsed.namespace;
|
|
45
|
+
var eventKey = parsed.eventKey;
|
|
46
|
+
|
|
47
|
+
// 初始化命名空间和事件数组
|
|
48
|
+
if (!this.dict[namespace]) {
|
|
49
|
+
this.dict[namespace] = {};
|
|
50
|
+
this.namespaces[namespace] = true;
|
|
51
|
+
}
|
|
52
|
+
if (!this.dict[namespace][eventKey]) {
|
|
53
|
+
this.dict[namespace][eventKey] = [];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// 确保func是函数
|
|
57
|
+
if (typeof func !== 'function') {
|
|
58
|
+
throw new Error('事件处理函数必须是一个函数');
|
|
32
59
|
}
|
|
60
|
+
|
|
61
|
+
// 设置默认名称
|
|
33
62
|
if (!name) {
|
|
34
|
-
name = func.name ||
|
|
63
|
+
name = func.name || `handler_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
|
|
35
64
|
}
|
|
65
|
+
|
|
66
|
+
// 应用节流或防抖
|
|
67
|
+
var wrappedFunc = func;
|
|
68
|
+
if (options.throttle) {
|
|
69
|
+
wrappedFunc = this._throttle(func, options.throttle);
|
|
70
|
+
} else if (options.debounce) {
|
|
71
|
+
wrappedFunc = this._debounce(func, options.debounce);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// 创建事件对象
|
|
36
75
|
var obj = {
|
|
37
76
|
name,
|
|
38
|
-
func,
|
|
39
|
-
|
|
77
|
+
func: wrappedFunc,
|
|
78
|
+
original_func: func,
|
|
79
|
+
times,
|
|
80
|
+
priority,
|
|
81
|
+
options,
|
|
82
|
+
created_at: Date.now()
|
|
40
83
|
};
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
84
|
+
|
|
85
|
+
// 检查是否已存在同名事件
|
|
86
|
+
var eventList = this.dict[namespace][eventKey];
|
|
87
|
+
var existingIndex = -1;
|
|
88
|
+
for (var i = 0; i < eventList.length; i++) {
|
|
89
|
+
if (eventList[i].name === name) {
|
|
90
|
+
existingIndex = i;
|
|
45
91
|
break;
|
|
46
92
|
}
|
|
47
93
|
}
|
|
48
|
-
|
|
49
|
-
|
|
94
|
+
|
|
95
|
+
if (existingIndex >= 0) {
|
|
96
|
+
// 覆盖已存在的同名监听器
|
|
97
|
+
Object.assign(eventList[existingIndex], obj);
|
|
98
|
+
// 重新排序
|
|
99
|
+
this._sortEventsByPriority(eventList);
|
|
100
|
+
return { namespace, index: existingIndex, name };
|
|
50
101
|
} else {
|
|
51
|
-
|
|
102
|
+
// 检查监听器数量是否超过限制
|
|
103
|
+
var max_listeners = this.config.max_listeners;
|
|
104
|
+
if (max_listeners > 0 && eventList.length >= max_listeners) {
|
|
105
|
+
$.log.warn(`警告: '${namespace}:${eventKey}' 事件的监听器数量已达到 ${max_listeners},可能导致内存泄漏。使用 setMaxListeners() 方法可以增加限制。`);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// 添加新事件
|
|
109
|
+
eventList.push(obj);
|
|
110
|
+
// 按优先级排序
|
|
111
|
+
this._sortEventsByPriority(eventList);
|
|
112
|
+
return { namespace, index: eventList.length - 1, name };
|
|
52
113
|
}
|
|
53
|
-
return events[key].length - 1;
|
|
54
114
|
}
|
|
55
115
|
|
|
56
116
|
/**
|
|
57
117
|
* 监听事件(仅执行一次)
|
|
58
|
-
* @param {String} key
|
|
118
|
+
* @param {String} key 事件关键,支持namespace:key格式
|
|
59
119
|
* @param {Object} func 触发函数
|
|
60
120
|
* @param {String} name 增加名称,方便删除,当出现相同名称时会被覆盖
|
|
61
|
-
* @
|
|
121
|
+
* @param {Number} priority 优先级,数字越小优先级越高,默认为0
|
|
122
|
+
* @param {Object} options 其他选项
|
|
123
|
+
* @param {String} namespace 可选的显式命名空间
|
|
124
|
+
* @returns {Object} 返回事件信息对象 {namespace, index, name}
|
|
62
125
|
*/
|
|
63
|
-
Eventer.prototype.once = function (key, func, name) {
|
|
64
|
-
return this.on(key, func, name, 1);
|
|
126
|
+
Eventer.prototype.once = function (key, func, name, priority = 0, options = {}, namespace = null) {
|
|
127
|
+
return this.on(key, func, name, 1, priority, options, namespace);
|
|
65
128
|
}
|
|
66
129
|
|
|
67
130
|
/**
|
|
68
|
-
*
|
|
69
|
-
* @param {String} key
|
|
131
|
+
* 执行事件(支持中间件和命名空间)
|
|
132
|
+
* @param {String} key 事件关键字,支持namespace:key格式
|
|
70
133
|
* @param {Object} params 传递参数
|
|
134
|
+
* @param {Object} options 执行选项
|
|
135
|
+
* @returns {Promise<Array>} 返回所有事件处理的结果数组
|
|
71
136
|
*/
|
|
72
137
|
Eventer.prototype.run = async function (key, ...params) {
|
|
73
|
-
|
|
74
|
-
var
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
138
|
+
// 解析命名空间
|
|
139
|
+
var { namespace, eventKey } = this._parseKey(key);
|
|
140
|
+
var fullEventKey = key; // 完整的事件键,包含命名空间
|
|
141
|
+
|
|
142
|
+
// 获取事件列表
|
|
143
|
+
var eventList = this.dict[namespace] && this.dict[namespace][eventKey];
|
|
144
|
+
|
|
145
|
+
// 创建上下文对象
|
|
146
|
+
var startTime = Date.now();
|
|
147
|
+
var context = {
|
|
148
|
+
namespace,
|
|
149
|
+
event: eventKey,
|
|
150
|
+
full_event: fullEventKey,
|
|
151
|
+
params,
|
|
152
|
+
results: [],
|
|
153
|
+
start_time: startTime,
|
|
154
|
+
executed: 0,
|
|
155
|
+
error_count: 0
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
var arr = []; // 存储需要移除的事件
|
|
159
|
+
var results = []; // 存储执行结果
|
|
160
|
+
|
|
161
|
+
// 如果有事件处理函数,执行它们
|
|
162
|
+
if (eventList && eventList.length > 0) {
|
|
163
|
+
// 执行前置中间件
|
|
164
|
+
try {
|
|
165
|
+
await this._runMiddlewares('before', context);
|
|
166
|
+
} catch (middlewareError) {
|
|
167
|
+
$.log.error(`事件中间件执行失败 [${namespace}:${eventKey}]`, middlewareError);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// 执行事件处理函数
|
|
171
|
+
for (var i = 0; i < eventList.length; i++) {
|
|
78
172
|
try {
|
|
79
|
-
var o =
|
|
80
|
-
|
|
81
|
-
|
|
173
|
+
var o = eventList[i];
|
|
174
|
+
context.executed++;
|
|
175
|
+
|
|
176
|
+
// 执行事件处理函数
|
|
177
|
+
var result = await o.func.apply(o, params);
|
|
178
|
+
results.push(result);
|
|
179
|
+
context.results.push(result);
|
|
180
|
+
|
|
181
|
+
// 处理执行次数限制
|
|
82
182
|
if (o.times >= 0) {
|
|
83
183
|
o.times--;
|
|
84
184
|
if (o.times <= 0) {
|
|
@@ -86,97 +186,235 @@ Eventer.prototype.run = async function (key, ...params) {
|
|
|
86
186
|
}
|
|
87
187
|
}
|
|
88
188
|
} catch (e) {
|
|
89
|
-
|
|
90
|
-
|
|
189
|
+
context.error_count++;
|
|
190
|
+
$.log.error(`事件执行失败 [${namespace}:${eventKey}] - ${o.name}`, e);
|
|
191
|
+
results.push({
|
|
192
|
+
_error: true,
|
|
193
|
+
error: e,
|
|
194
|
+
handler: o.name
|
|
195
|
+
});
|
|
196
|
+
context.results.push(results[results.length - 1]);
|
|
91
197
|
}
|
|
92
198
|
}
|
|
199
|
+
|
|
200
|
+
// 移除已执行完的事件
|
|
93
201
|
for (var i = 0; i < arr.length; i++) {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
202
|
+
this.del(`${namespace}:${eventKey}`, arr[i]);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// 执行后置中间件
|
|
206
|
+
try {
|
|
207
|
+
context.end_time = Date.now();
|
|
208
|
+
context.duration = context.end_time - startTime;
|
|
209
|
+
await this._runMiddlewares('after', context);
|
|
210
|
+
} catch (middlewareError) {
|
|
211
|
+
$.log.error(`事件后置中间件执行失败 [${namespace}:${eventKey}]`, middlewareError);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// 执行事件链(只触发下一级事件,不重复执行当前事件)
|
|
216
|
+
if (this.config.chain_enabled && this.eventChains[fullEventKey]) {
|
|
217
|
+
try {
|
|
218
|
+
// 直接触发下一级事件,避免重复执行当前事件
|
|
219
|
+
await this._triggerNextChainEvents(fullEventKey, params);
|
|
220
|
+
} catch (chainError) {
|
|
221
|
+
$.log.error(`事件链执行失败 [${fullEventKey}]`, chainError);
|
|
99
222
|
}
|
|
100
223
|
}
|
|
224
|
+
|
|
225
|
+
return results;
|
|
101
226
|
}
|
|
102
227
|
|
|
103
228
|
/**
|
|
104
229
|
* 触发事件
|
|
105
|
-
* @param {String} key
|
|
230
|
+
* @param {String} key 事件关键,支持namespace:key格式
|
|
106
231
|
* @param {Object} params 传递参数
|
|
232
|
+
* @returns {Promise<Array>} 返回所有事件处理的结果数组
|
|
107
233
|
*/
|
|
108
234
|
Eventer.prototype.emit = function (key, ...params) {
|
|
109
|
-
this.run(key, ...params);
|
|
235
|
+
return this.run(key, ...params);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* 触发所有命名空间的特定事件
|
|
240
|
+
* @param {String} eventKey 事件关键字(不含命名空间)
|
|
241
|
+
* @param {Object} params 传递参数
|
|
242
|
+
* @returns {Promise<Object>} 返回各命名空间的执行结果 {namespace1: results1, namespace2: results2}
|
|
243
|
+
*/
|
|
244
|
+
Eventer.prototype.emitAll = async function (eventKey, ...params) {
|
|
245
|
+
var results = {};
|
|
246
|
+
// 确保遍历所有命名空间,包括动态创建的
|
|
247
|
+
for (var namespace in this.dict) {
|
|
248
|
+
// 确保命名空间在namespaces映射中
|
|
249
|
+
if (!this.namespaces[namespace]) {
|
|
250
|
+
this.namespaces[namespace] = true;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// 检查该命名空间下是否存在该事件
|
|
254
|
+
if (this.dict[namespace] && this.dict[namespace][eventKey]) {
|
|
255
|
+
// 直接使用命名空间和事件键执行
|
|
256
|
+
var context = {
|
|
257
|
+
namespace,
|
|
258
|
+
event: eventKey,
|
|
259
|
+
params
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
var eventList = this.dict[namespace][eventKey];
|
|
263
|
+
var namespaceResults = [];
|
|
264
|
+
var arr = []; // 存储需要移除的事件
|
|
265
|
+
|
|
266
|
+
// 执行事件处理函数
|
|
267
|
+
for (var i = 0; i < eventList.length; i++) {
|
|
268
|
+
try {
|
|
269
|
+
var o = eventList[i];
|
|
270
|
+
|
|
271
|
+
// 执行事件处理函数
|
|
272
|
+
var result = await o.func.apply(o, params);
|
|
273
|
+
namespaceResults.push(result);
|
|
274
|
+
|
|
275
|
+
// 处理执行次数限制
|
|
276
|
+
if (o.times >= 0) {
|
|
277
|
+
o.times--;
|
|
278
|
+
if (o.times <= 0) {
|
|
279
|
+
arr.push(o.name);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
} catch (e) {
|
|
283
|
+
// 记录错误但不中断执行
|
|
284
|
+
$.log.error(`事件执行失败 [${namespace}:${eventKey}] - ${eventList[i].name}`, e);
|
|
285
|
+
namespaceResults.push({
|
|
286
|
+
_error: true,
|
|
287
|
+
error: e,
|
|
288
|
+
handler: eventList[i].name
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// 移除已执行完的事件
|
|
294
|
+
for (var i = 0; i < arr.length; i++) {
|
|
295
|
+
this.del(`${namespace}:${eventKey}`, arr[i]);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
results[namespace] = namespaceResults;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
return results;
|
|
110
302
|
}
|
|
111
303
|
|
|
112
304
|
/**
|
|
113
305
|
* 删除事件
|
|
114
|
-
* @param {String} key
|
|
306
|
+
* @param {String} key 事件关键字,支持namespace:key格式
|
|
115
307
|
* @param {Number|String} indexOrName 事件集索引或名称
|
|
116
308
|
* @returns {Boolean} 删除成功返回true,否则返回false
|
|
117
309
|
*/
|
|
118
|
-
Eventer.prototype.
|
|
119
|
-
|
|
120
|
-
|
|
310
|
+
Eventer.prototype.off = function (key, indexOrName) {
|
|
311
|
+
// 解析命名空间
|
|
312
|
+
var { namespace, eventKey } = this._parseKey(key);
|
|
313
|
+
|
|
314
|
+
// 检查事件是否存在
|
|
315
|
+
if (!this.dict[namespace] || !this.dict[namespace][eventKey]) {
|
|
121
316
|
return false;
|
|
122
317
|
}
|
|
123
318
|
|
|
319
|
+
var events = this.dict[namespace][eventKey];
|
|
320
|
+
|
|
124
321
|
if (indexOrName) {
|
|
125
|
-
var list = events[key];
|
|
126
322
|
if (typeof (indexOrName) === "number") {
|
|
127
|
-
|
|
128
|
-
|
|
323
|
+
// 按索引删除
|
|
324
|
+
if (indexOrName >= 0 && indexOrName < events.length) {
|
|
325
|
+
events.splice(indexOrName, 1);
|
|
129
326
|
return true;
|
|
130
327
|
}
|
|
131
328
|
} else {
|
|
132
329
|
// 根据名称删除事件
|
|
133
|
-
for (var j =
|
|
134
|
-
if (
|
|
135
|
-
|
|
330
|
+
for (var j = events.length - 1; j >= 0; j--) {
|
|
331
|
+
if (events[j].name === indexOrName) {
|
|
332
|
+
events.splice(j, 1);
|
|
136
333
|
return true;
|
|
137
334
|
}
|
|
138
335
|
}
|
|
139
336
|
}
|
|
140
337
|
} else {
|
|
141
338
|
// 删除整个事件
|
|
142
|
-
delete
|
|
339
|
+
delete this.dict[namespace][eventKey];
|
|
143
340
|
return true;
|
|
144
341
|
}
|
|
145
342
|
return false;
|
|
146
343
|
};
|
|
147
344
|
|
|
345
|
+
Eventer.prototype.add = Eventer.prototype.on;
|
|
346
|
+
Eventer.prototype.del = Eventer.prototype.off;
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* 删除命名空间中的所有事件
|
|
350
|
+
* @param {String} namespace 命名空间
|
|
351
|
+
* @returns {Boolean} 删除成功返回true,否则返回false
|
|
352
|
+
*/
|
|
353
|
+
Eventer.prototype.clearNamespace = function (namespace) {
|
|
354
|
+
if (!namespace || !this.dict[namespace]) {
|
|
355
|
+
return false;
|
|
356
|
+
}
|
|
357
|
+
delete this.dict[namespace];
|
|
358
|
+
delete this.namespaces[namespace];
|
|
359
|
+
return true;
|
|
360
|
+
}
|
|
361
|
+
|
|
148
362
|
/**
|
|
149
363
|
* 获取事件列表
|
|
150
|
-
* @param {String} key
|
|
364
|
+
* @param {String} key 事件关键字,如果为空则获取所有事件,支持namespace:key格式
|
|
151
365
|
* @returns {Array|Object} 返回事件列表或所有事件对象
|
|
152
366
|
*/
|
|
153
367
|
Eventer.prototype.getEvents = function (key) {
|
|
154
368
|
if (key) {
|
|
155
|
-
|
|
369
|
+
// 解析命名空间
|
|
370
|
+
var { namespace, eventKey } = this._parseKey(key);
|
|
371
|
+
return this.dict[namespace] && this.dict[namespace][eventKey] ? [...this.dict[namespace][eventKey]] : [];
|
|
372
|
+
}
|
|
373
|
+
// 返回深拷贝的所有事件
|
|
374
|
+
var result = {};
|
|
375
|
+
for (var namespace in this.dict) {
|
|
376
|
+
result[namespace] = {};
|
|
377
|
+
for (var eventKey in this.dict[namespace]) {
|
|
378
|
+
result[namespace][eventKey] = [...this.dict[namespace][eventKey]];
|
|
379
|
+
}
|
|
156
380
|
}
|
|
157
|
-
return
|
|
381
|
+
return result;
|
|
158
382
|
};
|
|
159
383
|
|
|
384
|
+
/**
|
|
385
|
+
* 获取所有命名空间
|
|
386
|
+
* @returns {Array} 返回所有命名空间数组
|
|
387
|
+
*/
|
|
388
|
+
Eventer.prototype.getNamespaces = function () {
|
|
389
|
+
return Object.keys(this.namespaces);
|
|
390
|
+
}
|
|
391
|
+
|
|
160
392
|
/**
|
|
161
393
|
* 清空所有事件
|
|
162
394
|
*/
|
|
163
395
|
Eventer.prototype.clear = function () {
|
|
164
396
|
this.dict = {};
|
|
397
|
+
this.namespaces = {};
|
|
398
|
+
// 保留默认命名空间
|
|
399
|
+
this.namespaces[this.config.default_namespace] = true;
|
|
165
400
|
};
|
|
166
401
|
|
|
167
402
|
/**
|
|
168
403
|
* 检查事件是否存在
|
|
169
|
-
* @param {String} key
|
|
404
|
+
* @param {String} key 事件关键字,支持namespace:key格式
|
|
170
405
|
* @param {String} name 事件名称(可选)
|
|
171
406
|
* @returns {Boolean} 事件存在返回true,否则返回false
|
|
172
407
|
*/
|
|
173
408
|
Eventer.prototype.has = function (key, name) {
|
|
174
|
-
|
|
409
|
+
// 解析命名空间
|
|
410
|
+
var { namespace, eventKey } = this._parseKey(key);
|
|
411
|
+
|
|
412
|
+
if (!this.dict[namespace] || !this.dict[namespace][eventKey]) {
|
|
175
413
|
return false;
|
|
176
414
|
}
|
|
177
415
|
|
|
178
416
|
if (name) {
|
|
179
|
-
var list = this.dict[
|
|
417
|
+
var list = this.dict[namespace][eventKey];
|
|
180
418
|
for (var i = 0; i < list.length; i++) {
|
|
181
419
|
if (list[i].name === name) {
|
|
182
420
|
return true;
|
|
@@ -190,21 +428,335 @@ Eventer.prototype.has = function (key, name) {
|
|
|
190
428
|
|
|
191
429
|
/**
|
|
192
430
|
* 获取事件数量
|
|
193
|
-
* @param {String} key
|
|
431
|
+
* @param {String} key 事件关键字,如果为空则获取所有事件数量,支持namespace:key格式或namespace:*格式
|
|
194
432
|
* @returns {Number} 返回事件数量
|
|
195
433
|
*/
|
|
196
434
|
Eventer.prototype.count = function (key) {
|
|
197
435
|
if (key) {
|
|
198
|
-
|
|
436
|
+
// 解析可能的命名空间模式
|
|
437
|
+
if (key.endsWith(':*')) {
|
|
438
|
+
// 统计命名空间下所有事件
|
|
439
|
+
var namespace = key.split(':')[0];
|
|
440
|
+
if (this.dict[namespace]) {
|
|
441
|
+
var total = 0;
|
|
442
|
+
for (var eventKey in this.dict[namespace]) {
|
|
443
|
+
total += this.dict[namespace][eventKey].length;
|
|
444
|
+
}
|
|
445
|
+
return total;
|
|
446
|
+
}
|
|
447
|
+
return 0;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// 解析具体事件
|
|
451
|
+
var { namespace, eventKey } = this._parseKey(key);
|
|
452
|
+
return this.dict[namespace] && this.dict[namespace][eventKey] ? this.dict[namespace][eventKey].length : 0;
|
|
199
453
|
}
|
|
200
454
|
|
|
455
|
+
// 统计所有事件
|
|
201
456
|
var total = 0;
|
|
202
|
-
for (var
|
|
203
|
-
|
|
457
|
+
for (var namespace in this.dict) {
|
|
458
|
+
for (var eventKey in this.dict[namespace]) {
|
|
459
|
+
total += this.dict[namespace][eventKey].length;
|
|
460
|
+
}
|
|
204
461
|
}
|
|
205
462
|
return total;
|
|
206
463
|
};
|
|
207
464
|
|
|
465
|
+
/**
|
|
466
|
+
* 添加事件中间件
|
|
467
|
+
* @param {String} type 中间件类型,'before' 或 'after'
|
|
468
|
+
* @param {Function} middleware 中间件函数,接收context参数
|
|
469
|
+
* @returns {Eventer} 返回当前实例,支持链式调用
|
|
470
|
+
*/
|
|
471
|
+
Eventer.prototype.use = function (type, middleware) {
|
|
472
|
+
if (type !== 'before' && type !== 'after') {
|
|
473
|
+
throw new Error('中间件类型必须是 "before" 或 "after"');
|
|
474
|
+
}
|
|
475
|
+
if (typeof middleware !== 'function') {
|
|
476
|
+
throw new Error('中间件必须是一个函数');
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
if (!this.middlewares[type]) {
|
|
480
|
+
this.middlewares[type] = [];
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
this.middlewares[type].push(middleware);
|
|
484
|
+
return this;
|
|
485
|
+
};
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* 添加事件链式触发关系
|
|
489
|
+
* @param {String} fromEvent 触发源事件,支持namespace:key格式
|
|
490
|
+
* @param {String|Array} toEvents 目标事件,可以是单个事件字符串或事件数组
|
|
491
|
+
* @returns {Eventer} 返回当前实例,支持链式调用
|
|
492
|
+
*/
|
|
493
|
+
Eventer.prototype.chain = function (fromEvent, toEvents) {
|
|
494
|
+
if (!fromEvent || typeof fromEvent !== 'string') {
|
|
495
|
+
throw new Error('触发源事件必须是一个非空字符串');
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
if (!toEvents) {
|
|
499
|
+
throw new Error('目标事件不能为空');
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
// 标准化为数组
|
|
503
|
+
var targets = Array.isArray(toEvents) ? toEvents : [toEvents];
|
|
504
|
+
for (var i = 0; i < targets.length; i++) {
|
|
505
|
+
if (typeof targets[i] !== 'string') {
|
|
506
|
+
throw new Error('目标事件必须是字符串类型');
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// 初始化事件链
|
|
511
|
+
if (!this.eventChains[fromEvent]) {
|
|
512
|
+
this.eventChains[fromEvent] = [];
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// 添加到事件链中,避免重复
|
|
516
|
+
for (var i = 0; i < targets.length; i++) {
|
|
517
|
+
if (this.eventChains[fromEvent].indexOf(targets[i]) === -1) {
|
|
518
|
+
this.eventChains[fromEvent].push(targets[i]);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
return this;
|
|
523
|
+
};
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* 移除事件链式触发关系
|
|
527
|
+
* @param {String} fromEvent 触发源事件
|
|
528
|
+
* @param {String|Array} toEvents 目标事件,不传则移除所有关联
|
|
529
|
+
* @returns {Eventer} 返回当前实例,支持链式调用
|
|
530
|
+
*/
|
|
531
|
+
Eventer.prototype.unchain = function (fromEvent, toEvents) {
|
|
532
|
+
if (!fromEvent || !this.eventChains[fromEvent]) {
|
|
533
|
+
return this;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
if (!toEvents) {
|
|
537
|
+
// 移除所有关联
|
|
538
|
+
delete this.eventChains[fromEvent];
|
|
539
|
+
} else {
|
|
540
|
+
// 移除指定关联
|
|
541
|
+
var targets = Array.isArray(toEvents) ? toEvents : [toEvents];
|
|
542
|
+
this.eventChains[fromEvent] = this.eventChains[fromEvent].filter(event => {
|
|
543
|
+
return targets.indexOf(event) === -1;
|
|
544
|
+
});
|
|
545
|
+
|
|
546
|
+
// 如果没有关联了,清理数组
|
|
547
|
+
if (this.eventChains[fromEvent].length === 0) {
|
|
548
|
+
delete this.eventChains[fromEvent];
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
return this;
|
|
553
|
+
};
|
|
554
|
+
|
|
555
|
+
/**
|
|
556
|
+
* 获取事件链关系
|
|
557
|
+
* @param {String} event 事件名称,不传则获取所有
|
|
558
|
+
* @returns {Object|Array} 事件链关系
|
|
559
|
+
*/
|
|
560
|
+
Eventer.prototype.getChains = function (event) {
|
|
561
|
+
if (event) {
|
|
562
|
+
return this.eventChains[event] || [];
|
|
563
|
+
}
|
|
564
|
+
return { ...this.eventChains };
|
|
565
|
+
};
|
|
566
|
+
|
|
567
|
+
/**
|
|
568
|
+
* 触发下一级事件链事件
|
|
569
|
+
* @private
|
|
570
|
+
* @param {String} currentEvent 当前触发的事件
|
|
571
|
+
* @param {Array} params 传递的参数
|
|
572
|
+
* @returns {Promise<void>}
|
|
573
|
+
*/
|
|
574
|
+
Eventer.prototype._triggerNextChainEvents = async function (currentEvent, params) {
|
|
575
|
+
if (!this.config.chain_enabled || !this.eventChains[currentEvent]) {
|
|
576
|
+
return;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
// 循环触发下一级事件
|
|
580
|
+
for (var nextEvent of this.eventChains[currentEvent]) {
|
|
581
|
+
await this._executeEventChainItem(nextEvent, params);
|
|
582
|
+
}
|
|
583
|
+
};
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* 执行单个链上事件(包含中间件)
|
|
587
|
+
* @private
|
|
588
|
+
* @param {String} eventKey 要执行的事件
|
|
589
|
+
* @param {Array} params 参数
|
|
590
|
+
* @returns {Promise<Array>} 执行结果
|
|
591
|
+
*/
|
|
592
|
+
Eventer.prototype._executeEventChainItem = async function (eventKey, params) {
|
|
593
|
+
// 解析命名空间
|
|
594
|
+
var { namespace, eventKey: innerEventKey } = this._parseKey(eventKey);
|
|
595
|
+
var eventList = this.dict[namespace] && this.dict[namespace][innerEventKey];
|
|
596
|
+
var results = [];
|
|
597
|
+
|
|
598
|
+
// 创建上下文对象
|
|
599
|
+
var startTime = Date.now();
|
|
600
|
+
var context = {
|
|
601
|
+
namespace,
|
|
602
|
+
event: innerEventKey,
|
|
603
|
+
full_event: eventKey,
|
|
604
|
+
params,
|
|
605
|
+
results: [],
|
|
606
|
+
start_time: startTime,
|
|
607
|
+
executed: 0,
|
|
608
|
+
error_count: 0
|
|
609
|
+
};
|
|
610
|
+
|
|
611
|
+
// 如果有事件处理函数,执行它们
|
|
612
|
+
if (eventList && eventList.length > 0) {
|
|
613
|
+
// 执行前置中间件
|
|
614
|
+
try {
|
|
615
|
+
await this._runMiddlewares('before', context);
|
|
616
|
+
} catch (middlewareError) {
|
|
617
|
+
$.log.error(`事件链中间件执行失败 [${namespace}:${innerEventKey}]`, middlewareError);
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
// 执行事件处理函数
|
|
621
|
+
for (var i = 0; i < eventList.length; i++) {
|
|
622
|
+
try {
|
|
623
|
+
var o = eventList[i];
|
|
624
|
+
context.executed++;
|
|
625
|
+
|
|
626
|
+
// 执行事件处理函数
|
|
627
|
+
var result = await o.func.apply(o, params);
|
|
628
|
+
results.push(result);
|
|
629
|
+
context.results.push(result);
|
|
630
|
+
|
|
631
|
+
// 处理执行次数限制
|
|
632
|
+
if (o.times >= 0) {
|
|
633
|
+
o.times--;
|
|
634
|
+
if (o.times <= 0) {
|
|
635
|
+
this.del(`${namespace}:${innerEventKey}`, o.name);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
} catch (e) {
|
|
639
|
+
context.error_count++;
|
|
640
|
+
$.log.error(`事件链执行失败 [${namespace}:${innerEventKey}] - ${o.name}`, e);
|
|
641
|
+
results.push({
|
|
642
|
+
_error: true,
|
|
643
|
+
error: e,
|
|
644
|
+
handler: o.name
|
|
645
|
+
});
|
|
646
|
+
context.results.push(results[results.length - 1]);
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
// 执行后置中间件
|
|
651
|
+
try {
|
|
652
|
+
context.end_time = Date.now();
|
|
653
|
+
context.duration = context.end_time - startTime;
|
|
654
|
+
await this._runMiddlewares('after', context);
|
|
655
|
+
} catch (middlewareError) {
|
|
656
|
+
$.log.error(`事件链后置中间件执行失败 [${namespace}:${innerEventKey}]`, middlewareError);
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
// 递归触发下一级事件
|
|
661
|
+
if (this.eventChains[eventKey]) {
|
|
662
|
+
await this._triggerNextChainEvents(eventKey, params);
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
return results;
|
|
666
|
+
};
|
|
667
|
+
|
|
668
|
+
/**
|
|
669
|
+
* 并行执行事件(提高性能)
|
|
670
|
+
* @param {String} key 事件关键字,支持namespace:key格式
|
|
671
|
+
* @param {Object} params 传递参数
|
|
672
|
+
* @returns {Promise<Array>} 返回所有事件处理的结果数组
|
|
673
|
+
*/
|
|
674
|
+
Eventer.prototype.runParallel = async function (key, ...params) {
|
|
675
|
+
// 解析命名空间
|
|
676
|
+
var { namespace, eventKey } = this._parseKey(key);
|
|
677
|
+
|
|
678
|
+
// 获取事件列表
|
|
679
|
+
var eventList = this.dict[namespace] && this.dict[namespace][eventKey];
|
|
680
|
+
if (!eventList || eventList.length === 0) {
|
|
681
|
+
return [];
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
// 创建上下文对象
|
|
685
|
+
var startTime = Date.now();
|
|
686
|
+
var context = {
|
|
687
|
+
namespace,
|
|
688
|
+
event: eventKey,
|
|
689
|
+
params,
|
|
690
|
+
start_time: startTime
|
|
691
|
+
};
|
|
692
|
+
|
|
693
|
+
// 执行前置中间件
|
|
694
|
+
try {
|
|
695
|
+
await this._runMiddlewares('before', context);
|
|
696
|
+
} catch (middlewareError) {
|
|
697
|
+
$.log.error(`事件中间件执行失败 [${namespace}:${eventKey}]`, middlewareError);
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
// 并行执行所有事件
|
|
701
|
+
var tasks = eventList.map(o => this._executeTask(o, params));
|
|
702
|
+
var results = await Promise.allSettled(tasks);
|
|
703
|
+
|
|
704
|
+
// 处理结果和清理
|
|
705
|
+
var arr = [];
|
|
706
|
+
var processedResults = [];
|
|
707
|
+
|
|
708
|
+
for (var i = 0; i < results.length; i++) {
|
|
709
|
+
var result = results[i];
|
|
710
|
+
var event = eventList[i];
|
|
711
|
+
|
|
712
|
+
if (result.status === 'fulfilled') {
|
|
713
|
+
processedResults.push(result.value);
|
|
714
|
+
} else {
|
|
715
|
+
$.log.error(`事件执行失败 [${namespace}:${eventKey}] - ${event.name}`, result.reason);
|
|
716
|
+
processedResults.push({
|
|
717
|
+
_error: true,
|
|
718
|
+
error: result.reason,
|
|
719
|
+
handler: event.name
|
|
720
|
+
});
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
// 处理执行次数限制
|
|
724
|
+
if (event.times >= 0) {
|
|
725
|
+
event.times--;
|
|
726
|
+
if (event.times <= 0) {
|
|
727
|
+
arr.push(event.name);
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
// 移除已执行完的事件
|
|
733
|
+
for (var i = 0; i < arr.length; i++) {
|
|
734
|
+
this.del(`${namespace}:${eventKey}`, arr[i]);
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
// 执行后置中间件
|
|
738
|
+
try {
|
|
739
|
+
context.end_time = Date.now();
|
|
740
|
+
context.duration = context.end_time - startTime;
|
|
741
|
+
context.results = processedResults;
|
|
742
|
+
await this._runMiddlewares('after', context);
|
|
743
|
+
} catch (middlewareError) {
|
|
744
|
+
$.log.error(`事件后置中间件执行失败 [${namespace}:${eventKey}]`, middlewareError);
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
return processedResults;
|
|
748
|
+
};
|
|
749
|
+
|
|
750
|
+
/**
|
|
751
|
+
* 异步触发事件(并行执行)
|
|
752
|
+
* @param {String} key 事件关键字,支持namespace:key格式
|
|
753
|
+
* @param {Object} params 传递参数
|
|
754
|
+
* @returns {Promise<Array>} 返回所有事件处理的结果数组
|
|
755
|
+
*/
|
|
756
|
+
Eventer.prototype.emitParallel = function (key, ...params) {
|
|
757
|
+
return this.runParallel(key, ...params);
|
|
758
|
+
};
|
|
759
|
+
|
|
208
760
|
/**
|
|
209
761
|
* 防止内存泄漏警告
|
|
210
762
|
* @param {Number} n 最大监听器数量
|
|
@@ -219,7 +771,7 @@ Eventer.prototype.setMaxListeners = function (n) {
|
|
|
219
771
|
|
|
220
772
|
/**
|
|
221
773
|
* 批量添加事件
|
|
222
|
-
* @param {Object} eventsMap 事件映射对象 { key: [func1, func2...] }
|
|
774
|
+
* @param {Object} eventsMap 事件映射对象 { key: [func1, func2...] 或 key: {func, options} }
|
|
223
775
|
* @returns {Eventer} 返回当前实例,支持链式调用
|
|
224
776
|
*/
|
|
225
777
|
Eventer.prototype.onMany = function (eventsMap) {
|
|
@@ -230,14 +782,129 @@ Eventer.prototype.onMany = function (eventsMap) {
|
|
|
230
782
|
for (var key in eventsMap) {
|
|
231
783
|
var handlers = eventsMap[key];
|
|
232
784
|
if (Array.isArray(handlers)) {
|
|
233
|
-
handlers.forEach(
|
|
234
|
-
if (typeof
|
|
235
|
-
this.on(key,
|
|
785
|
+
handlers.forEach((handler, index) => {
|
|
786
|
+
if (typeof handler === 'function') {
|
|
787
|
+
this.on(key, handler, `handler_${index}`);
|
|
788
|
+
} else if (typeof handler === 'object' && handler.func) {
|
|
789
|
+
var { func, name, priority, options } = handler;
|
|
790
|
+
this.on(key, func, name || `handler_${index}`, -1, priority, options);
|
|
236
791
|
}
|
|
237
792
|
});
|
|
793
|
+
} else if (typeof handlers === 'object' && handlers.func) {
|
|
794
|
+
var { func, name, priority, options } = handlers;
|
|
795
|
+
this.on(key, func, name, -1, priority, options);
|
|
238
796
|
}
|
|
239
797
|
}
|
|
240
798
|
return this;
|
|
241
799
|
};
|
|
242
800
|
|
|
243
|
-
|
|
801
|
+
// 私有方法
|
|
802
|
+
|
|
803
|
+
/**
|
|
804
|
+
* 解析事件键,提取命名空间和事件名
|
|
805
|
+
* @private
|
|
806
|
+
* @param {String} key 事件键
|
|
807
|
+
* @returns {Object} {namespace, eventKey}
|
|
808
|
+
*/
|
|
809
|
+
Eventer.prototype._parseKey = function (key) {
|
|
810
|
+
var parts = key.split(':');
|
|
811
|
+
var namespace = this.config.default_namespace;
|
|
812
|
+
var eventKey = key;
|
|
813
|
+
|
|
814
|
+
if (parts.length > 1) {
|
|
815
|
+
namespace = parts[0];
|
|
816
|
+
eventKey = parts.slice(1).join(':');
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
return { namespace, eventKey };
|
|
820
|
+
};
|
|
821
|
+
|
|
822
|
+
/**
|
|
823
|
+
* 按优先级排序事件
|
|
824
|
+
* @private
|
|
825
|
+
* @param {Array} events 事件列表
|
|
826
|
+
*/
|
|
827
|
+
Eventer.prototype._sortEventsByPriority = function (events) {
|
|
828
|
+
events.sort((a, b) => {
|
|
829
|
+
// 先按优先级排序
|
|
830
|
+
if (a.priority !== b.priority) {
|
|
831
|
+
return a.priority - b.priority;
|
|
832
|
+
}
|
|
833
|
+
// 优先级相同时按创建时间排序
|
|
834
|
+
return a.created_at - b.created_at;
|
|
835
|
+
});
|
|
836
|
+
};
|
|
837
|
+
|
|
838
|
+
/**
|
|
839
|
+
* 执行事件中间件
|
|
840
|
+
* @private
|
|
841
|
+
* @param {String} type 中间件类型
|
|
842
|
+
* @param {Object} context 上下文对象
|
|
843
|
+
*/
|
|
844
|
+
Eventer.prototype._runMiddlewares = async function(type, context) {
|
|
845
|
+
if (!this.middlewares[type]) {
|
|
846
|
+
return;
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
for (let middleware of this.middlewares[type]) {
|
|
850
|
+
try {
|
|
851
|
+
await middleware(context);
|
|
852
|
+
} catch (err) {
|
|
853
|
+
$.log.error(`中间件执行失败 [${type}] - ${err.message}`);
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
};
|
|
857
|
+
|
|
858
|
+
/**
|
|
859
|
+
* 执行单个事件任务
|
|
860
|
+
* @private
|
|
861
|
+
* @param {Object} event 事件对象
|
|
862
|
+
* @param {Array} params 参数数组
|
|
863
|
+
* @returns {Promise<any>} 执行结果
|
|
864
|
+
*/
|
|
865
|
+
Eventer.prototype._executeTask = async function (event, params) {
|
|
866
|
+
return event.func.apply(event, params);
|
|
867
|
+
};
|
|
868
|
+
|
|
869
|
+
/**
|
|
870
|
+
* 函数节流
|
|
871
|
+
* @private
|
|
872
|
+
* @param {Function} func 要节流的函数
|
|
873
|
+
* @param {Number} limit 时间限制(毫秒)
|
|
874
|
+
* @returns {Function} 节流后的函数
|
|
875
|
+
*/
|
|
876
|
+
Eventer.prototype._throttle = function (func, limit) {
|
|
877
|
+
var inThrottle;
|
|
878
|
+
return function() {
|
|
879
|
+
var args = arguments;
|
|
880
|
+
var context = this;
|
|
881
|
+
if (!inThrottle) {
|
|
882
|
+
func.apply(context, args);
|
|
883
|
+
inThrottle = true;
|
|
884
|
+
setTimeout(() => inThrottle = false, limit);
|
|
885
|
+
}
|
|
886
|
+
};
|
|
887
|
+
};
|
|
888
|
+
|
|
889
|
+
/**
|
|
890
|
+
* 函数防抖
|
|
891
|
+
* @private
|
|
892
|
+
* @param {Function} func 要防抖的函数
|
|
893
|
+
* @param {Number} wait 等待时间(毫秒)
|
|
894
|
+
* @returns {Function} 防抖后的函数
|
|
895
|
+
*/
|
|
896
|
+
Eventer.prototype._debounce = function (func, wait) {
|
|
897
|
+
var timeout;
|
|
898
|
+
return function() {
|
|
899
|
+
var args = arguments;
|
|
900
|
+
var context = this;
|
|
901
|
+
clearTimeout(timeout);
|
|
902
|
+
timeout = setTimeout(() => func.apply(context, args), wait);
|
|
903
|
+
};
|
|
904
|
+
};
|
|
905
|
+
|
|
906
|
+
/**
|
|
907
|
+
* 导出单例实例
|
|
908
|
+
*/
|
|
909
|
+
exports.Eventer = Eventer;
|
|
910
|
+
exports.eventer = new Eventer();
|