mm_expand 1.9.3 → 1.9.4

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/README.md CHANGED
@@ -416,6 +416,69 @@ await $.sleep(2000, obj, 'ok');
416
416
  - 参数:同$.eventer.runParallel
417
417
  - 返回值:包含执行结果和取消方法的对象
418
418
 
419
+ ##### 异步事件触发
420
+
421
+ ##### $.eventer.emitWait(eventName, ...args)
422
+ - 描述:异步触发事件,按顺序执行等待完成
423
+ - 参数:
424
+ - eventName: 事件名称(支持命名空间格式:namespace:event)
425
+ - ...args: 传递给事件处理器的参数
426
+ - 返回值:Promise,按优先级顺序执行所有监听器
427
+ - 示例:
428
+ ```javascript
429
+ // 顺序执行用户登录事件的所有监听器
430
+ await $.eventer.emitWait('user:login', { id: 1, name: '张三' });
431
+ ```
432
+
433
+ ##### $.eventer.emitAsync(eventName, ...args)
434
+ - 描述:异步触发事件,并发执行不等待
435
+ - 参数:
436
+ - eventName: 事件名称(支持命名空间格式:namespace:event)
437
+ - ...args: 传递给事件处理器的参数
438
+ - 返回值:布尔值,表示是否有监听器被触发
439
+ - 示例:
440
+ ```javascript
441
+ // 异步触发数据更新事件,不等待执行结果
442
+ $.eventer.emitAsync('data:update', { timestamp: Date.now() });
443
+ ```
444
+
445
+ ##### $.eventer.emitAll(eventName, ...args)
446
+ - 描述:异步触发事件,并发执行等待完成
447
+ - 参数:
448
+ - eventName: 事件名称(支持命名空间格式:namespace:event)
449
+ - ...args: 传递给事件处理器的参数
450
+ - 返回值:Promise<Array>,包含所有监听器的执行结果
451
+ - 示例:
452
+ ```javascript
453
+ // 并发执行所有数据处理监听器,等待全部完成
454
+ const results = await $.eventer.emitAll('data:process', { items: [...] });
455
+ ```
456
+
457
+ ##### $.eventer.emitRace(eventName, ...args)
458
+ - 描述:异步触发事件,竞争执行(第一个完成即返回)
459
+ - 参数:
460
+ - eventName: 事件名称(支持命名空间格式:namespace:event)
461
+ - ...args: 传递给事件处理器的参数
462
+ - 返回值:Promise,第一个完成的监听器结果
463
+ - 示例:
464
+ ```javascript
465
+ // 竞争执行多个缓存策略,使用第一个返回的结果
466
+ const fastestResult = await $.eventer.emitRace('cache:get', { key: 'user_data' });
467
+ ```
468
+
469
+ ##### $.eventer.emitWaterfall(eventName, initialValue, ...args)
470
+ - 描述:异步触发事件,瀑布流执行(前一个结果传递给下一个)
471
+ - 参数:
472
+ - eventName: 事件名称(支持命名空间格式:namespace:event)
473
+ - initialValue: 初始值
474
+ - ...args: 传递给事件处理器的参数
475
+ - 返回值:Promise,最后一个监听器的执行结果
476
+ - 示例:
477
+ ```javascript
478
+ // 瀑布流处理数据,每个处理器接收前一个的结果
479
+ const finalResult = await $.eventer.emitWaterfall('data:pipeline', initialData, { stage: 'processing' });
480
+ ```
481
+
419
482
  ##### 事件控制
420
483
 
421
484
  ##### $.eventer.pause(key)
@@ -561,16 +624,17 @@ A: 目前提供基本的JavaScript支持,TypeScript类型定义正在规划中
561
624
  ## npm发布信息
562
625
 
563
626
  ### 发布状态
564
- - **当前版本**: 1.9.2
627
+ - **当前版本**: 1.9.3
565
628
  - **npm包名**: mm_expand
566
629
  - **发布状态**: 已准备发布
567
630
 
568
631
  ### 发布前检查清单
569
- - ✅ 所有测试通过(42/42)
632
+ - ✅ 所有测试通过(87/87,100%通过率)
570
633
  - ✅ 文档已更新
571
634
  - ✅ 依赖项已正确配置
572
635
  - ✅ 包信息完整
573
636
  - ✅ 许可证文件存在
637
+ - ✅ 事件系统性能优化完成
574
638
 
575
639
  ### 发布命令
576
640
  ```bash
package/README_EN.md CHANGED
@@ -20,6 +20,32 @@ This library extends JavaScript native object prototypes with comprehensive data
20
20
  - **Data Conversion Tools**: JSON, XML, URL parameters, and other format conversion functions
21
21
  - **Lightweight and Efficient**: Core functions are lightweight with good performance optimization
22
22
  - **Cross-Platform Compatibility**: Supports Node.js and modern browser environments
23
+ - **Sanguosha Card System**: Complete card game system with card management, character system, and battle mechanics
24
+
25
+ ### Key Features
26
+
27
+ #### String Enhancement
28
+ - **$()** - String prototype function enhancement
29
+ - **Chinese Pinyin Processing** - Support Chinese to Pinyin, Pinyin initials
30
+ - **XML/JSON Conversion** - Support XML and JSON mutual conversion
31
+ - **String Formatting** - Support various formatting operations
32
+
33
+ #### Array Enhancement
34
+ - **Array Operations** - Support array CRUD, sorting, filtering, etc.
35
+ - **Array Conversion** - Support array to string, object conversion
36
+
37
+ #### Object Enhancement
38
+ - **Object Operations** - Support deep clone, merge, traversal, etc.
39
+ - **Object Validation** - Support object property validation and type checking
40
+
41
+ #### Date Enhancement
42
+ - **Date Formatting** - Support multiple date format outputs
43
+ - **Date Calculation** - Support date addition/subtraction, comparison
44
+
45
+ #### Event System
46
+ - **Event Listening** - Support asynchronous event listening and triggering
47
+ - **Event Priority** - Support event execution priority setting
48
+ - **Event Cancellation** - Support event execution cancellation mechanism
23
49
 
24
50
  ## Installation
25
51
 
@@ -416,6 +442,69 @@ await $.sleep(2000, obj, 'ok');
416
442
  - Parameters: Same as $.eventer.runParallel
417
443
  - Returns: Object containing execution results and cancel method
418
444
 
445
+ ##### Asynchronous Event Triggering
446
+
447
+ ##### $.eventer.emitWait(eventName, ...args)
448
+ - Description: Asynchronously trigger events, execute sequentially and wait for completion
449
+ - Parameters:
450
+ - eventName: Event name (supports namespace format: namespace:event)
451
+ - ...args: Arguments passed to event handlers
452
+ - Returns: Promise, executes all listeners in priority order
453
+ - Example:
454
+ ```javascript
455
+ // Execute all user login event listeners sequentially
456
+ await $.eventer.emitWait('user:login', { id: 1, name: 'John' });
457
+ ```
458
+
459
+ ##### $.eventer.emitAsync(eventName, ...args)
460
+ - Description: Asynchronously trigger events, execute concurrently without waiting
461
+ - Parameters:
462
+ - eventName: Event name (supports namespace format: namespace:event)
463
+ - ...args: Arguments passed to event handlers
464
+ - Returns: Boolean, indicates whether any listeners were triggered
465
+ - Example:
466
+ ```javascript
467
+ // Asynchronously trigger data update event without waiting for results
468
+ $.eventer.emitAsync('data:update', { timestamp: Date.now() });
469
+ ```
470
+
471
+ ##### $.eventer.emitAll(eventName, ...args)
472
+ - Description: Asynchronously trigger events, execute concurrently and wait for completion
473
+ - Parameters:
474
+ - eventName: Event name (supports namespace format: namespace:event)
475
+ - ...args: Arguments passed to event handlers
476
+ - Returns: Promise<Array>, contains execution results of all listeners
477
+ - Example:
478
+ ```javascript
479
+ // Execute all data processing listeners concurrently and wait for all to complete
480
+ const results = await $.eventer.emitAll('data:process', { items: [...] });
481
+ ```
482
+
483
+ ##### $.eventer.emitRace(eventName, ...args)
484
+ - Description: Asynchronously trigger events, race execution (returns first completed result)
485
+ - Parameters:
486
+ - eventName: Event name (supports namespace format: namespace:event)
487
+ - ...args: Arguments passed to event handlers
488
+ - Returns: Promise, result of the first completed listener
489
+ - Example:
490
+ ```javascript
491
+ // Race execution of multiple cache strategies, use the first returned result
492
+ const fastestResult = await $.eventer.emitRace('cache:get', { key: 'user_data' });
493
+ ```
494
+
495
+ ##### $.eventer.emitWaterfall(eventName, initialValue, ...args)
496
+ - Description: Asynchronously trigger events, waterfall execution (pass result to next)
497
+ - Parameters:
498
+ - eventName: Event name (supports namespace format: namespace:event)
499
+ - initialValue: Initial value
500
+ - ...args: Arguments passed to event handlers
501
+ - Returns: Promise, result of the last listener
502
+ - Example:
503
+ ```javascript
504
+ // Waterfall data processing, each handler receives the previous result
505
+ const finalResult = await $.eventer.emitWaterfall('data:pipeline', initialData, { stage: 'processing' });
506
+ ```
507
+
419
508
  ##### Event Control
420
509
 
421
510
  ##### $.eventer.pause(key)
@@ -540,6 +629,19 @@ Welcome to submit Issues and Pull Requests! Please ensure your code follows thes
540
629
  3. Write test cases to ensure functionality
541
630
  4. Run tests before submitting to ensure no new issues are introduced
542
631
 
632
+ ## Release Status
633
+ - **Current Version**: 1.9.3
634
+ - **npm Package Name**: mm_expand
635
+ - **Release Status**: Ready for release
636
+
637
+ ### Pre-release Checklist
638
+ - ✅ All tests passed (87/87, 100% pass rate)
639
+ - ✅ Documentation updated
640
+ - ✅ Dependencies correctly configured
641
+ - ✅ Package information complete
642
+ - ✅ License file exists
643
+ - ✅ Event system performance optimization completed
644
+
543
645
  ## Changelog
544
646
 
545
647
  Detailed changelog can be found on the project's [Release page](https://gitee.com/qiuwenwu91/mm_expand/releases).
package/lib/base.js CHANGED
@@ -62,37 +62,37 @@ Base.prototype.logger = function (level, message, ...args) {
62
62
  * 初始化监听
63
63
  */
64
64
  Base.prototype._initListen = function () {
65
- this.on('init.before', (ctx) => {
65
+ this.on('init:before', (ctx) => {
66
66
  this.status = 'initing';
67
67
  this._initCore(...ctx.params);
68
68
  });
69
- this.on('start.before', (ctx) => {
69
+ this.on('start:before', (ctx) => {
70
70
  this.status = 'starting';
71
71
  });
72
- this.on('start.after', (ctx) => {
72
+ this.on('start:after', (ctx) => {
73
73
  this.status = 'running';
74
74
  });
75
- this.on('stop.before', (ctx) => {
75
+ this.on('stop:before', (ctx) => {
76
76
  this.status = 'stopping';
77
77
  });
78
- this.on('stop.after', (ctx) => {
78
+ this.on('stop:after', (ctx) => {
79
79
  this.status = 'stopped';
80
80
  });
81
- this.on('restart.before', (ctx) => {
81
+ this.on('restart:before', (ctx) => {
82
82
  this.status = 'restarting';
83
83
  });
84
- this.on('restart.after', (ctx) => {
84
+ this.on('restart:after', (ctx) => {
85
85
  this.status = 'running';
86
86
  });
87
- this.on('destroy.before', (ctx) => {
87
+ this.on('destroy:before', (ctx) => {
88
88
  this.status = 'destroying';
89
89
  });
90
- this.on('destroy.check', (ctx) => {
90
+ this.on('destroy:check', (ctx) => {
91
91
  if (this.status !== 'stopped') {
92
92
  ctx.error = new Error('销毁前必须先停止');
93
93
  }
94
94
  });
95
- this.on('destroy.after', (ctx) => {
95
+ this.on('destroy:after', (ctx) => {
96
96
  this.status = 'destroyed';
97
97
  });
98
98
  };
@@ -185,28 +185,119 @@ Base.prototype.do = async function (method, ...args) {
185
185
  }
186
186
 
187
187
  let ctx = {
188
- method: method,
188
+ method,
189
189
  params: args,
190
190
  result: undefined,
191
191
  error: undefined
192
192
  };
193
- this.emit(method + '_before', ctx);
193
+
194
+ // 1. 前置处理(顺序执行)
195
+ await this.emitWait(method + ':before', ctx);
196
+
194
197
  try {
195
- this.emit(method + '_check', ctx);
196
- if (ctx.error) {
197
- throw ctx.error;
198
- } else if (ctx.result) {
199
- return ctx.result;
198
+ // 2. 检查阶段(竞争执行)- 任何一个检查失败就停止
199
+ const checkResult = await this.emitRace(method + ':check', ctx);
200
+
201
+ // 处理检查结果
202
+ if (checkResult) {
203
+ if (checkResult.status === 'rejected') {
204
+ // 检查阶段有错误,直接返回
205
+ ctx.error = checkResult.error;
206
+ return ctx.result;
207
+ } else if (checkResult.status === 'fulfilled' && checkResult.result) {
208
+ // 检查阶段返回了有效结果,直接使用
209
+ ctx.result = checkResult.result;
210
+ }
211
+ }
212
+
213
+ // 3. 执行主方法(如果没有被检查阶段拦截)
214
+ if (!ctx.result) {
215
+ ctx.result = await this[method](...ctx.params);
200
216
  }
201
- ctx.result = await this[method](...ctx.params);
217
+
218
+ // 4. 渲染阶段(瀑布式执行)- 适合数据处理管道
202
219
  if (ctx.result) {
203
- this.emit(method + '_render', ctx);
220
+ let result = await this.emitWaterfall(method + ':render', ctx.result, ctx);
221
+ if (result) {
222
+ ctx.result = result;
223
+ }
204
224
  }
205
225
  } catch (error) {
206
226
  ctx.error = error;
207
- this.emit(method + '_error', ctx);
227
+ }
228
+
229
+ // 5. 错误处理(异步执行,不阻塞)
230
+ if (ctx.error) {
231
+ await this.emitAsync(method + ':error', ctx);
208
232
  this.logger('error', `[${this.constructor.name}] 执行方法${method}出错:`, ctx.error);
209
233
  }
234
+
235
+ // 6. 后置处理(顺序执行)
236
+ await this.emitWait(method + ':after', ctx);
237
+
238
+ return ctx.result;
239
+ }
240
+
241
+ /**
242
+ * 快速执行方法
243
+ * @param {String} method 方法名称
244
+ * @param {...Object} args 参数列表
245
+ * @return {Object} 返回执行结果
246
+ */
247
+ Base.prototype.doEasy = async function (method, ...args) {
248
+ // 快速检查方法是否存在
249
+ if (!this[method]) {
250
+ throw new Error(`[${this.constructor.name}] 方法${method}不存在`);
251
+ }
252
+
253
+ try {
254
+ // 直接执行主方法,跳过所有事件处理
255
+ return await this[method](...args);
256
+ } catch (error) {
257
+ // 简单错误处理
258
+ this.logger('error', `[${this.constructor.name}] 快速执行方法${method}出错:`, error);
259
+ throw error;
260
+ }
261
+ }
262
+
263
+ /**
264
+ * 智能执行方法(自动选择do或doEasy)
265
+ * @param {String} method 方法名称
266
+ * @param {...Object} args 参数列表
267
+ * @param {Object} options 执行选项
268
+ * @return {Object} 返回执行结果
269
+ */
270
+ Base.prototype.doSmart = async function (method, ...args) {
271
+ // 提取选项参数
272
+ let options = {};
273
+ if (args.length > 0 && typeof args[args.length - 1] === 'object') {
274
+ options = args.pop();
275
+ }
276
+
277
+ // 检查是否有监听器
278
+ const hasListeners = this._hasEventListeners(method);
279
+
280
+ // 根据选项和监听器情况选择执行方式
281
+ if (options.fast || !hasListeners) {
282
+ // 快速执行:无监听器或明确要求快速
283
+ return await this.doEasy(method, ...args);
284
+ } else {
285
+ // 完整事件驱动执行
286
+ return await this.do(method, ...args);
287
+ }
288
+ }
289
+
290
+ /**
291
+ * 检查方法是否有事件监听器
292
+ * @param {String} method 方法名称
293
+ * @return {Boolean} 是否有监听器
294
+ * @private
295
+ */
296
+ Base.prototype._hasEventListeners = function (method) {
297
+ return this.listenerCount(method + ':before') > 0 ||
298
+ this.listenerCount(method + ':check') > 0 ||
299
+ this.listenerCount(method + ':render') > 0 ||
300
+ this.listenerCount(method + ':after') > 0;
210
301
  }
211
302
 
212
303
  /**
package/lib/event.js CHANGED
@@ -30,7 +30,7 @@ Event.prototype.logger = function (level, message, ...args) {
30
30
  Event.prototype.emitWait = async function (event, ...args) {
31
31
  const listeners = this.listeners(event);
32
32
  if (listeners.length === 0) {
33
- reject(new Error(`事件 ${event} 没有监听者`));
33
+ return;
34
34
  } else {
35
35
  for (const listener of listeners) {
36
36
  try {
@@ -63,12 +63,12 @@ Event.prototype.emitAsync = async function (event, ...args) {
63
63
  .catch(error => {
64
64
  // 错误处理 - 记录但不抛出
65
65
  this.logger('error', `Async listener error for event ${event}:`, error);
66
- this.emit('async.error', error, event, args);
66
+ this.emit('async:error', error, event, args);
67
67
  });
68
68
  } catch (syncError) {
69
69
  // 同步错误处理
70
70
  this.logger('error', `Sync listener error for event ${event}:`, syncError);
71
- this.emit('sync.error', syncError, event, args);
71
+ this.emit('sync:error', syncError, event, args);
72
72
  }
73
73
  });
74
74
 
package/lib/eventer.js CHANGED
@@ -408,13 +408,173 @@ Eventer.prototype.emit = function (key, ...params) {
408
408
  return { ...result, cancel: () => result.then(r => r && typeof r.cancel === 'function' && r.cancel()) };
409
409
  };
410
410
 
411
+ /**
412
+ * 异步触发事件,按顺序执行等待完成
413
+ * @param {String} key 事件关键字,支持namespace:key格式
414
+ * @param {...any} args 事件参数
415
+ * @returns {Promise} - 事件触发结果
416
+ */
417
+ Eventer.prototype.emitWait = async function (key, ...args) {
418
+ // 解析命名空间
419
+ var { namespace, key } = this._parseKey(key);
420
+ var fullkey = `${namespace}:${key}`;
421
+
422
+ // 获取事件列表
423
+ var list = this._dict[namespace] && this._dict[namespace][key];
424
+
425
+ if (!list || list.length === 0) {
426
+ throw new Error(`事件 ${fullkey} 没有监听者`);
427
+ }
428
+
429
+ // 按优先级排序后顺序执行
430
+ var sortedList = [...list].sort((a, b) => a.priority - b.priority);
431
+
432
+ for (const handler of sortedList) {
433
+ try {
434
+ await handler.func(...args);
435
+ } catch (err) {
436
+ this.logger('error', `事件监听器执行失败 [${fullkey}]:`, err);
437
+ throw err;
438
+ }
439
+ }
440
+ };
441
+
442
+ /**
443
+ * 异步触发事件,并发执行不等待
444
+ * @param {String} key 事件关键字,支持namespace:key格式
445
+ * @param {...any} args 事件参数
446
+ * @returns {Boolean} - 是否有监听者
447
+ */
448
+ Eventer.prototype.emitAsync = async function (key, ...args) {
449
+ // 解析命名空间
450
+ var { namespace, key } = this._parseKey(key);
451
+ var fullkey = `${namespace}:${key}`;
452
+
453
+ // 获取事件列表
454
+ var list = this._dict[namespace] && this._dict[namespace][key];
455
+
456
+ if (!list || list.length === 0) {
457
+ return false;
458
+ }
459
+
460
+ // 立即启动所有监听器,但不等待
461
+ list.forEach(handler => {
462
+ try {
463
+ // 使用 Promise.resolve 确保异步执行
464
+ Promise.resolve(handler.func(...args))
465
+ .catch(error => {
466
+ // 错误处理 - 记录但不抛出
467
+ this.logger('error', `异步监听器错误 [${fullkey}]:`, error);
468
+ this.emit('async:error', error, fullkey, args);
469
+ });
470
+ } catch (syncError) {
471
+ // 同步错误处理
472
+ this.logger('error', `同步监听器错误 [${fullkey}]:`, syncError);
473
+ this.emit('sync:error', syncError, fullkey, args);
474
+ }
475
+ });
476
+
477
+ return true;
478
+ };
479
+
480
+ /**
481
+ * 异步触发事件,并发执行等待完成
482
+ * @param {String} key 事件关键字,支持namespace:key格式
483
+ * @param {...any} args 事件参数
484
+ * @returns {Promise<Array>} - 所有监听器的执行结果
485
+ */
486
+ Eventer.prototype.emitAll = async function (key, ...args) {
487
+ // 解析命名空间
488
+ var { namespace, key } = this._parseKey(key);
489
+
490
+ // 获取事件列表
491
+ var list = this._dict[namespace] && this._dict[namespace][key];
492
+
493
+ if (!list || list.length === 0) {
494
+ return [];
495
+ }
496
+
497
+ const promises = list.map(handler => {
498
+ try {
499
+ return Promise.resolve(handler.func(...args));
500
+ } catch (error) {
501
+ return Promise.reject(error);
502
+ }
503
+ });
504
+
505
+ return await Promise.all(promises);
506
+ };
507
+
508
+ /**
509
+ * 异步触发事件,竞争执行
510
+ * @param {String} key 事件关键字,支持namespace:key格式
511
+ * @param {...any} args 事件参数
512
+ * @returns {Promise} - 第一个完成的结果
513
+ */
514
+ Eventer.prototype.emitRace = async function (key, ...args) {
515
+ // 解析命名空间
516
+ var { namespace, key } = this._parseKey(key);
517
+
518
+ // 获取事件列表
519
+ var list = this._dict[namespace] && this._dict[namespace][key];
520
+
521
+ if (!list || list.length === 0) {
522
+ return null;
523
+ }
524
+
525
+ const promises = list.map((handler, index) =>
526
+ Promise.resolve(handler.func(...args))
527
+ .then(result => ({ index, result, status: 'fulfilled' }))
528
+ .catch(error => ({ index, error, status: 'rejected' }))
529
+ );
530
+
531
+ // 使用 Promise.race 获取第一个完成的结果
532
+ return await Promise.race(promises);
533
+ };
534
+
535
+ /**
536
+ * 异步触发事件,瀑布流执行
537
+ * @param {String} key 事件关键字,支持namespace:key格式
538
+ * @param {*} value 初始值
539
+ * @param {...any} args 事件参数
540
+ * @returns {Promise} - 最后一个事件监听者的结果
541
+ */
542
+ Eventer.prototype.emitWaterfall = async function (key, value, ...args) {
543
+ // 解析命名空间
544
+ var { namespace, key } = this._parseKey(key);
545
+ var fullkey = `${namespace}:${key}`;
546
+
547
+ // 获取事件列表
548
+ var list = this._dict[namespace] && this._dict[namespace][key];
549
+
550
+ if (!list || list.length === 0) {
551
+ return value;
552
+ }
553
+
554
+ let val = value;
555
+
556
+ // 按优先级排序
557
+ var sortedList = [...list].sort((a, b) => a.priority - b.priority);
558
+
559
+ for (const handler of sortedList) {
560
+ try {
561
+ val = await handler.func(val, ...args);
562
+ } catch (error) {
563
+ this.logger('error', `瀑布流执行失败 [${fullkey}]:`, error);
564
+ throw error;
565
+ }
566
+ }
567
+
568
+ return val;
569
+ };
570
+
411
571
  /**
412
572
  * 触发所有命名空间的特定事件
413
573
  * @param {String} key 事件关键字(不含命名空间)
414
574
  * @param {Object} params 传递参数
415
575
  * @returns {Promise<Object>} 返回各命名空间的执行结果 {namespace1: results1, namespace2: results2}
416
576
  */
417
- Eventer.prototype.emitAll = async function (key, ...params) {
577
+ Eventer.prototype.emitAllNamespaces = async function (key, ...params) {
418
578
  var results = {};
419
579
  // 确保遍历所有命名空间,包括动态创建的
420
580
  for (var name in this._dict) {
@@ -770,47 +930,47 @@ Eventer.prototype.unchain = function (fromEvent, toEvents) {
770
930
  var fullFromEvent = `${fromNamespace}:${fromkey}`;
771
931
 
772
932
  // 如果源事件不存在事件链,直接返回
773
- if (!this._chain[fullFromEvent]) {
774
- return this;
775
- }
776
-
777
- if (toEvents) {
778
- // 移除特定目标事件
779
- var targetEvents = Array.isArray(toEvents) ? toEvents : [toEvents];
780
- for (var i = 0; i < targetEvents.length; i++) {
781
- var toEvent = targetEvents[i];
782
- if (typeof toEvent !== 'string') {
783
- throw new Error('目标事件必须是非空字符串');
784
- }
785
-
786
- // 解析目标事件
787
- var { namespace: toNamespace, key: tokey } = this._parseKey(toEvent);
788
- var fullToEvent = `${toNamespace}:${tokey}`;
933
+ if (!this._chain[fullFromEvent]) {
934
+ return this;
935
+ }
789
936
 
790
- // 检查事件链是否存在
791
- if (!this._chain[fullFromEvent]) {
792
- this.logger('warn', `事件链不存在: ${fullFromEvent} -> ${fullToEvent}`);
793
- continue;
794
- }
937
+ if (toEvents) {
938
+ // 移除特定目标事件
939
+ var targetEvents = Array.isArray(toEvents) ? toEvents : [toEvents];
940
+ for (var i = 0; i < targetEvents.length; i++) {
941
+ var toEvent = targetEvents[i];
942
+ if (typeof toEvent !== 'string') {
943
+ throw new Error('目标事件必须是非空字符串');
944
+ }
795
945
 
796
- // 查找并删除事件链
797
- var index = this._chain[fullFromEvent].indexOf(fullToEvent);
798
- if (index === -1) {
799
- this.logger('warn', `事件链不存在: ${fullFromEvent} -> ${fullToEvent}`);
800
- continue;
801
- }
946
+ // 解析目标事件
947
+ var { namespace: toNamespace, key: tokey } = this._parseKey(toEvent);
948
+ var fullToEvent = `${toNamespace}:${tokey}`;
802
949
 
803
- this._chain[fullFromEvent].splice(index, 1);
950
+ // 检查事件链是否存在
951
+ if (!this._chain[fullFromEvent]) {
952
+ this.logger('warn', `事件链不存在: ${fullFromEvent} -> ${fullToEvent}`);
953
+ continue;
804
954
  }
805
955
 
806
- // 如果事件链为空,则删除整个事件链
807
- if (this._chain[fullFromEvent].length === 0) {
808
- delete this._chain[fullFromEvent];
956
+ // 查找并删除事件链
957
+ var index = this._chain[fullFromEvent].indexOf(fullToEvent);
958
+ if (index === -1) {
959
+ this.logger('warn', `事件链不存在: ${fullFromEvent} -> ${fullToEvent}`);
960
+ continue;
809
961
  }
810
- } else {
811
- // 移除整个事件链
962
+
963
+ this._chain[fullFromEvent].splice(index, 1);
964
+ }
965
+
966
+ // 如果事件链为空,则删除整个事件链
967
+ if (this._chain[fullFromEvent].length === 0) {
812
968
  delete this._chain[fullFromEvent];
813
969
  }
970
+ } else {
971
+ // 移除整个事件链
972
+ delete this._chain[fullFromEvent];
973
+ }
814
974
 
815
975
  return this;
816
976
  };