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 CHANGED
@@ -1,84 +1,184 @@
1
1
  /**
2
- * 事件类
2
+ * 事件类 - 增强版EventBus实现
3
3
  */
4
4
  class Eventer {
5
5
  /**
6
- * 构造函数
7
- * @param {Object} config 配置参数
8
- */
9
- constructor(config) {
10
- this.config = Object.assign({
11
- max_listeners: 10 // 最大监听器数量
12
- }, config || {});
13
- // 是否为插件
14
- this.is_plugin = false;
15
- // 事件字典
16
- this.dict = {};
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
- * @returns {Number} 返回事件索引位置
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
- var events = this.dict;
30
- if (!events[key]) {
31
- events[key] = [];
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 || 'default';
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
- times
77
+ func: wrappedFunc,
78
+ original_func: func,
79
+ times,
80
+ priority,
81
+ options,
82
+ created_at: Date.now()
40
83
  };
41
- var o = null;
42
- for (var i = 0; i < events[key].length; i++) {
43
- if (events[key][i].name === name) {
44
- o = events[key][i];
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
- if (o) {
49
- Object.assign(o, obj);
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
- events[key].push(obj);
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
- * @returns {Number} 返回事件索引位置
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
- var events = this.dict;
74
- var list = events[key];
75
- if (list) {
76
- var arr = [];
77
- for (var i = 0; i < list.length; i++) {
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 = list[i];
80
- // 简化Promise处理逻辑,避免可能的重复执行
81
- await o.func(...params);
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
- $.log.error("执行事件失败!", e);
90
- //TODO handle the exception
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
- for (var j = list.length - 1; j >= 0; j--) {
95
- if (list[j].name === arr[i]) {
96
- list.splice(j, 1);
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.del = function (key, indexOrName) {
119
- var events = this.dict;
120
- if (!events[key]) {
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
- if (indexOrName >= 0 && indexOrName < list.length) {
128
- list.splice(indexOrName, 1);
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 = list.length - 1; j >= 0; j--) {
134
- if (list[j].name === indexOrName) {
135
- list.splice(j, 1);
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 events[key];
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
- return this.dict[key] || [];
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 this.dict;
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
- if (!this.dict[key]) {
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[key];
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
- return this.dict[key] ? this.dict[key].length : 0;
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 k in this.dict) {
203
- total += this.dict[k].length;
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(func => {
234
- if (typeof func === 'function') {
235
- this.on(key, func);
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
- exports.Eventer = Eventer;
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();