mm_expand 2.4.2 → 2.4.3
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/base.js +3 -3
- package/lib/errors.js +1 -1
- package/lib/event.js +7 -7
- package/lib/eventer.js +2294 -2422
- package/lib/file.js +797 -797
- package/lib/global.js +2 -1
- package/lib/lang.js +6 -6
- package/lib/logger.js +2 -2
- package/lib/string.js +9 -9
- package/package.json +1 -1
package/lib/eventer.js
CHANGED
|
@@ -1,2422 +1,2294 @@
|
|
|
1
|
-
/* eslint-disable mm_eslint/function-name */
|
|
2
|
-
require('./global.js');
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* 事件类 - 增强版EventBus实现
|
|
6
|
-
*/
|
|
7
|
-
class Eventer {
|
|
8
|
-
static config = {
|
|
9
|
-
max_list: 10, // 最大监听器数量
|
|
10
|
-
default_name: 'default', // 默认命名空间
|
|
11
|
-
chain_enabled: true, // 是否启用链式触发
|
|
12
|
-
auto_clean: true, // 是否自动清理空的事件列表
|
|
13
|
-
error: null, // 全局错误处理函数
|
|
14
|
-
pause_enabled: true, // 是否启用暂停功能
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
// 日志对象
|
|
18
|
-
#logger = $.log || console;
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* 构造函数
|
|
22
|
-
* @param {object} config 配置参数
|
|
23
|
-
*/
|
|
24
|
-
constructor(config) {
|
|
25
|
-
this.config = {
|
|
26
|
-
...Eventer.config,
|
|
27
|
-
...config || {}
|
|
28
|
-
};
|
|
29
|
-
// 是否为插件
|
|
30
|
-
this.is_plugin = false;
|
|
31
|
-
// 事件字典 - 支持命名空间
|
|
32
|
-
this._dict = {};
|
|
33
|
-
// 事件中间件
|
|
34
|
-
this._middleware = [];
|
|
35
|
-
// 命名空间映射
|
|
36
|
-
this._space = {};
|
|
37
|
-
// 事件链映射 { 'event1': ['event2', 'event3'], 'space:event1': ['event4'] }
|
|
38
|
-
this._chain = {};
|
|
39
|
-
// 进行中的任务映射,用于取消操作
|
|
40
|
-
this._tasks = new Map();
|
|
41
|
-
// 暂停状态管理
|
|
42
|
-
this._paused = new Set(); // 暂停的单个事件
|
|
43
|
-
this._paused_space = new Set(); // 暂停的命名空间
|
|
44
|
-
this._paused_global = false; // 全局暂停状态
|
|
45
|
-
// 初始化默认命名空间
|
|
46
|
-
this._space[this.config.default_name] = true;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* 设置日志记录器
|
|
51
|
-
* @param {object} logger 日志记录器对象
|
|
52
|
-
*/
|
|
53
|
-
setLogger(logger) {
|
|
54
|
-
this.#logger = logger;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* 获取日志记录器
|
|
59
|
-
* @returns {object} 日志记录器对象
|
|
60
|
-
*/
|
|
61
|
-
getLogger() {
|
|
62
|
-
return this.#logger;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* 日志输出
|
|
67
|
-
* @param {string} level 日志级别
|
|
68
|
-
* @param {string} message 日志消息
|
|
69
|
-
* @param {...any} params 日志参数
|
|
70
|
-
*/
|
|
71
|
-
log(level, message, ...params) {
|
|
72
|
-
this.getLogger()[level](`[${this.constructor.name}] ${message}`, ...params);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* 初始化事件管理器
|
|
78
|
-
* @param {...any} args 初始化参数
|
|
79
|
-
* @returns {Eventer} 返回事件管理器实例
|
|
80
|
-
* @private
|
|
81
|
-
*/
|
|
82
|
-
Eventer.prototype._init = async function (...args) {
|
|
83
|
-
// 初始化逻辑
|
|
84
|
-
return this;
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* 初始化事件管理器
|
|
89
|
-
* @param {...any} args 初始化参数
|
|
90
|
-
* @returns {Eventer} 返回事件管理器实例
|
|
91
|
-
*/
|
|
92
|
-
Eventer.prototype.init = async function (...args) {
|
|
93
|
-
return this._init(...args);
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* 监听事件(支持命名空间和优先级)
|
|
98
|
-
* @param {string} key 事件关键字,支持space:key格式
|
|
99
|
-
* @param {object} func 触发函数
|
|
100
|
-
* @throws {Error} 事件关键字必须是非空字符串
|
|
101
|
-
* @throws {Error} 事件处理函数必须是一个函数
|
|
102
|
-
*/
|
|
103
|
-
Eventer.prototype._validateOnParams = function (key, func) {
|
|
104
|
-
if (!key || typeof key !== 'string') {
|
|
105
|
-
throw new Error('事件关键字必须是非空字符串');
|
|
106
|
-
}
|
|
107
|
-
if (typeof func !== 'function') {
|
|
108
|
-
throw new Error('事件处理函数必须是一个函数');
|
|
109
|
-
}
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
Eventer.prototype._parseEventKey = function (key, ns) {
|
|
113
|
-
let parsed = this._parseKey(key);
|
|
114
|
-
let space = ns || parsed.space;
|
|
115
|
-
let event_key = parsed.key;
|
|
116
|
-
let full_key = `${space}:${event_key}`;
|
|
117
|
-
return { space, event_key, full_key };
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
Eventer.prototype._initNamespace = function (space, event_key) {
|
|
121
|
-
if (!this._dict[space]) {
|
|
122
|
-
this._dict[space] = {};
|
|
123
|
-
this._space[space] = true;
|
|
124
|
-
}
|
|
125
|
-
if (!this._dict[space][event_key]) {
|
|
126
|
-
this._dict[space][event_key] = [];
|
|
127
|
-
}
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
Eventer.prototype._generateDefaultName = function (func) {
|
|
131
|
-
return func.name || `handler_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
Eventer.prototype._wrapFunction = function (func, params) {
|
|
135
|
-
let wrapped_func = func;
|
|
136
|
-
|
|
137
|
-
if (params.throttle) {
|
|
138
|
-
wrapped_func = this._throttle(func, params.throttle);
|
|
139
|
-
} else if (params.debounce) {
|
|
140
|
-
wrapped_func = this._debounce(func, params.debounce);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
if (params.timeout && typeof params.timeout === 'number' && params.timeout > 0) {
|
|
144
|
-
let original_func = wrapped_func;
|
|
145
|
-
wrapped_func = async function (...args) {
|
|
146
|
-
const timeoutPromise = new Promise((resolve, reject) => {
|
|
147
|
-
setTimeout(() => reject(new Error(`事件执行超时 (${params.timeout}ms)`)), params.timeout);
|
|
148
|
-
});
|
|
149
|
-
return Promise.race([original_func.apply(this, args), timeoutPromise]);
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
return wrapped_func;
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
Eventer.prototype._createHandlerObj = function (config) {
|
|
157
|
-
var handler = {
|
|
158
|
-
name: config.name,
|
|
159
|
-
func: config.wrapped_func,
|
|
160
|
-
original_func: config.func,
|
|
161
|
-
times: config.times,
|
|
162
|
-
priority: config.priority,
|
|
163
|
-
created_at: Date.now(),
|
|
164
|
-
last_executed: null
|
|
165
|
-
};
|
|
166
|
-
return handler;
|
|
167
|
-
};
|
|
168
|
-
|
|
169
|
-
Eventer.prototype._findHandlerIndex = function (list, name) {
|
|
170
|
-
for (let i = 0; i < list.length; i++) {
|
|
171
|
-
if (list[i].name === name) {
|
|
172
|
-
return i;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
return -1;
|
|
176
|
-
};
|
|
177
|
-
|
|
178
|
-
Eventer.prototype._checkListenerLimit = function (space, event_key, list) {
|
|
179
|
-
let max_list = this.config.max_list;
|
|
180
|
-
if (max_list > 0 && list.length >= max_list) {
|
|
181
|
-
this.log('warn', `警告: '${space}:${event_key}' 事件的监听器数量已达到 ${max_list},可能导致内存泄漏。使用 set_max_listeners() 方法可以增加限制。`);
|
|
182
|
-
}
|
|
183
|
-
};
|
|
184
|
-
|
|
185
|
-
Eventer.prototype._createHandlerResult = function (space, index, name, full_key) {
|
|
186
|
-
return {
|
|
187
|
-
space,
|
|
188
|
-
index,
|
|
189
|
-
name,
|
|
190
|
-
remove: () => this.off(full_key, name)
|
|
191
|
-
};
|
|
192
|
-
};
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* 监听事件(支持命名空间和优先级)
|
|
196
|
-
* @param {string} key 事件关键字,支持space:key格式
|
|
197
|
-
* @param {object} func 触发函数
|
|
198
|
-
* @param {string} name 增加名称,方便删除,当出现相同名称时会被覆盖
|
|
199
|
-
* @param {object} options 其他选项,如throttle、debounce、timeout等
|
|
200
|
-
* @returns {object} 返回事件信息对象 {space, index, name, remove},remove为移除该事件的函数
|
|
201
|
-
*/
|
|
202
|
-
Eventer.prototype.on = function (key, func, name, options) {
|
|
203
|
-
// 处理参数
|
|
204
|
-
let params = this._processOnParams(key, func, name, options);
|
|
205
|
-
|
|
206
|
-
// 验证参数
|
|
207
|
-
this._validateOnParams(params.key, params.func);
|
|
208
|
-
|
|
209
|
-
// 处理事件添加
|
|
210
|
-
return this._addEventHandler(params);
|
|
211
|
-
};
|
|
212
|
-
|
|
213
|
-
Eventer.prototype._processOnParams = function (key, func, name, options) {
|
|
214
|
-
// 支持两种调用方式:便捷方式和配置对象方式
|
|
215
|
-
if (typeof key === 'object' && key !== null) {
|
|
216
|
-
// 配置对象方式
|
|
217
|
-
return this._extractOnParams(key);
|
|
218
|
-
} else {
|
|
219
|
-
// 便捷方式
|
|
220
|
-
let opts = options || {};
|
|
221
|
-
return {
|
|
222
|
-
key: key,
|
|
223
|
-
func: func,
|
|
224
|
-
name: name,
|
|
225
|
-
times: opts.times || -1,
|
|
226
|
-
priority: opts.priority || 0,
|
|
227
|
-
ns: opts.ns || null
|
|
228
|
-
};
|
|
229
|
-
}
|
|
230
|
-
};
|
|
231
|
-
|
|
232
|
-
Eventer.prototype._addEventHandler = function (params) {
|
|
233
|
-
const { key:
|
|
234
|
-
times:
|
|
235
|
-
|
|
236
|
-
// 解析命名空间
|
|
237
|
-
const { space, event_key, full_key } = this._parseEventKey(
|
|
238
|
-
|
|
239
|
-
// 初始化命名空间和事件数组
|
|
240
|
-
this._initNamespace(space,
|
|
241
|
-
|
|
242
|
-
// 设置默认名称
|
|
243
|
-
let final_name =
|
|
244
|
-
|
|
245
|
-
// 应用节流或防抖
|
|
246
|
-
let wrapped_func = this._wrapFunction(
|
|
247
|
-
|
|
248
|
-
// 创建事件对象
|
|
249
|
-
let obj = this._createHandlerObj({
|
|
250
|
-
name: final_name,
|
|
251
|
-
wrapped_func: wrapped_func,
|
|
252
|
-
func:
|
|
253
|
-
times:
|
|
254
|
-
priority:
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
// 处理事件添加逻辑
|
|
258
|
-
return this._handleEventAddition({ space, event_key, full_key, final_name, obj });
|
|
259
|
-
};
|
|
260
|
-
|
|
261
|
-
Eventer.prototype._extractOnParams = function (config) {
|
|
262
|
-
return {
|
|
263
|
-
key: config.key,
|
|
264
|
-
func: config.func,
|
|
265
|
-
name: config.name,
|
|
266
|
-
times: config.times || -1,
|
|
267
|
-
priority: config.priority || 0,
|
|
268
|
-
ns: config.ns || null
|
|
269
|
-
};
|
|
270
|
-
};
|
|
271
|
-
|
|
272
|
-
Eventer.prototype._processOnceParams = function (key, func, name, options) {
|
|
273
|
-
// 支持两种调用方式:便捷方式和配置对象方式
|
|
274
|
-
if (typeof key === 'object' && key !== null) {
|
|
275
|
-
// 配置对象方式
|
|
276
|
-
let params = this._extractOnParams(key);
|
|
277
|
-
params.times = 1; // 强制设置为仅执行一次
|
|
278
|
-
return params;
|
|
279
|
-
} else {
|
|
280
|
-
// 便捷方式
|
|
281
|
-
let opts = options || {};
|
|
282
|
-
return {
|
|
283
|
-
key: key,
|
|
284
|
-
func: func,
|
|
285
|
-
name: name,
|
|
286
|
-
times: 1, // 强制设置为仅执行一次
|
|
287
|
-
priority: opts.priority || 0,
|
|
288
|
-
ns: opts.ns || null
|
|
289
|
-
};
|
|
290
|
-
}
|
|
291
|
-
};
|
|
292
|
-
|
|
293
|
-
Eventer.prototype._handleEventAddition = function (config) {
|
|
294
|
-
const { space, event_key, full_key, final_name, obj } = config;
|
|
295
|
-
let list = this._dict[space][event_key];
|
|
296
|
-
let idx = this._findHandlerIndex(list, final_name);
|
|
297
|
-
|
|
298
|
-
if (idx >= 0) {
|
|
299
|
-
// 覆盖已存在的同名监听器
|
|
300
|
-
Object.assign(list[idx], obj);
|
|
301
|
-
// 重新排序
|
|
302
|
-
this._sort(list);
|
|
303
|
-
return this._createHandlerResult(space, idx, final_name, full_key);
|
|
304
|
-
} else {
|
|
305
|
-
// 检查监听器数量是否超过限制
|
|
306
|
-
this._checkListenerLimit(space, event_key, list);
|
|
307
|
-
|
|
308
|
-
// 添加新事件
|
|
309
|
-
list.push(obj);
|
|
310
|
-
// 按优先级排序
|
|
311
|
-
this._sort(list);
|
|
312
|
-
return this._createHandlerResult(space, list.length - 1, final_name, full_key);
|
|
313
|
-
}
|
|
314
|
-
};
|
|
315
|
-
|
|
316
|
-
/**
|
|
317
|
-
* 监听事件(仅执行一次)
|
|
318
|
-
* @param {string | object} key 事件关键,支持space:key格式,或配置对象
|
|
319
|
-
* @param {object} func 触发函数
|
|
320
|
-
* @param {string} name 增加名称,方便删除,当出现相同名称时会被覆盖
|
|
321
|
-
* @param {object} options 其他选项
|
|
322
|
-
* @returns {object} 返回事件信息对象 {space, idx, name}
|
|
323
|
-
*/
|
|
324
|
-
Eventer.prototype.once = function (key, func, name, options) {
|
|
325
|
-
// 处理参数
|
|
326
|
-
let params = this._processOnceParams(key, func, name, options);
|
|
327
|
-
|
|
328
|
-
// 验证参数
|
|
329
|
-
this._validateOnParams(params.key, params.func);
|
|
330
|
-
|
|
331
|
-
// 处理事件添加
|
|
332
|
-
return this._addEventHandler(params);
|
|
333
|
-
};
|
|
334
|
-
|
|
335
|
-
/**
|
|
336
|
-
* 统一的事件执行引擎
|
|
337
|
-
* @param {string} key 事件关键字,支持space:key格式
|
|
338
|
-
* @throws {Error} 事件关键字必须是非空字符串
|
|
339
|
-
* @private
|
|
340
|
-
*/
|
|
341
|
-
Eventer.prototype._validateExec = function (key) {
|
|
342
|
-
if (!key || typeof key !== 'string') {
|
|
343
|
-
throw new Error('事件关键字必须是非空字符串');
|
|
344
|
-
}
|
|
345
|
-
};
|
|
346
|
-
|
|
347
|
-
Eventer.prototype._createCtx = function (key, params) {
|
|
348
|
-
let parsed = this._parseKey(key);
|
|
349
|
-
let space = parsed.space;
|
|
350
|
-
let event_key = parsed.key;
|
|
351
|
-
let full_key = `${space}:${event_key}`;
|
|
352
|
-
let start_time = Date.now();
|
|
353
|
-
|
|
354
|
-
const ctx = {
|
|
355
|
-
space,
|
|
356
|
-
event: event_key,
|
|
357
|
-
full_event: full_key,
|
|
358
|
-
params,
|
|
359
|
-
results: [],
|
|
360
|
-
start_time: start_time,
|
|
361
|
-
executed: 0,
|
|
362
|
-
error_count: 0,
|
|
363
|
-
cancelled: false,
|
|
364
|
-
cancel: () => {
|
|
365
|
-
ctx.cancelled = true;
|
|
366
|
-
this._cancelTasks(full_key);
|
|
367
|
-
}
|
|
368
|
-
};
|
|
369
|
-
|
|
370
|
-
return { ctx, space, event_key, full_key, start_time };
|
|
371
|
-
};
|
|
372
|
-
|
|
373
|
-
Eventer.prototype._cancelTasks = function (full_key) {
|
|
374
|
-
try {
|
|
375
|
-
if (this._tasks.has(full_key)) {
|
|
376
|
-
let tasks = this._tasks.get(full_key);
|
|
377
|
-
tasks.forEach(task => {
|
|
378
|
-
if (task && typeof task.cancel === 'function') {
|
|
379
|
-
try {
|
|
380
|
-
task.cancel();
|
|
381
|
-
} catch (cancel_error) {
|
|
382
|
-
this.log('error', `任务取消失败 [${full_key}] - ${task.id}`, cancel_error);
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
});
|
|
386
|
-
this._tasks.delete(full_key);
|
|
387
|
-
}
|
|
388
|
-
} catch (cancel_global_error) {
|
|
389
|
-
this.log('error', `任务取消过程异常 [${full_key}]`, cancel_global_error);
|
|
390
|
-
}
|
|
391
|
-
};
|
|
392
|
-
|
|
393
|
-
Eventer.prototype._initTaskList = function (full_key) {
|
|
394
|
-
try {
|
|
395
|
-
this._tasks.set(full_key, []);
|
|
396
|
-
} catch (task_init_error) {
|
|
397
|
-
this.log('error', `任务列表初始化失败 [${full_key}]`, task_init_error);
|
|
398
|
-
}
|
|
399
|
-
};
|
|
400
|
-
|
|
401
|
-
Eventer.prototype._runBeforeMiddleware = async function (ctx, full_key) {
|
|
402
|
-
try {
|
|
403
|
-
await this._runMiddleware('before', ctx);
|
|
404
|
-
if (ctx.cancelled) {
|
|
405
|
-
this._cleanupTasks(full_key);
|
|
406
|
-
return true;
|
|
407
|
-
}
|
|
408
|
-
return false;
|
|
409
|
-
} catch (error) {
|
|
410
|
-
this.log('error', `事件中间件执行失败 [${ctx.space}:${ctx.event}]`, error);
|
|
411
|
-
if (this.config.error_handler && typeof this.config.error_handler === 'function') {
|
|
412
|
-
this.config.error_handler(error, { type: 'middleware', stage: 'before', ctx });
|
|
413
|
-
}
|
|
414
|
-
return false;
|
|
415
|
-
}
|
|
416
|
-
};
|
|
417
|
-
|
|
418
|
-
Eventer.prototype._cleanupTasks = function (full_key) {
|
|
419
|
-
try {
|
|
420
|
-
this._tasks.delete(full_key);
|
|
421
|
-
} catch (cleanup_error) {
|
|
422
|
-
this.log('error', `任务清理失败 [${full_key}]`, cleanup_error);
|
|
423
|
-
}
|
|
424
|
-
};
|
|
425
|
-
|
|
426
|
-
Eventer.prototype._executeStrategy = async function (config) {
|
|
427
|
-
const { list, params, ctx, full_key, arr, options } = config;
|
|
428
|
-
|
|
429
|
-
try {
|
|
430
|
-
if (options.exec_mode === 'parallel') {
|
|
431
|
-
await this._executeParallel({ list, params, ctx, full_key, arr });
|
|
432
|
-
} else if (options.exec_mode === 'race') {
|
|
433
|
-
ctx.race_result = await this._executeRace({ list, params, ctx, full_key, arr });
|
|
434
|
-
} else if (options.exec_mode === 'waterfall') {
|
|
435
|
-
await this._executeWaterfall({
|
|
436
|
-
list, params, ctx, full_key, arr,
|
|
437
|
-
initial_value: options.initial_value
|
|
438
|
-
});
|
|
439
|
-
} else {
|
|
440
|
-
await this._executeSequential({ list, params, ctx, full_key, arr });
|
|
441
|
-
}
|
|
442
|
-
} catch (exec_error) {
|
|
443
|
-
this.log('error', `事件执行策略异常 [${full_key}]`, exec_error);
|
|
444
|
-
if (this.config.error_handler && typeof this.config.error_handler === 'function') {
|
|
445
|
-
this.config.error_handler(exec_error, { type: 'execution', ctx });
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
};
|
|
449
|
-
|
|
450
|
-
Eventer.prototype._removeEvents = function (space, key, arr) {
|
|
451
|
-
try {
|
|
452
|
-
for (let i = 0; i < arr.length; i++) {
|
|
453
|
-
this.del(`${space}:${key}`, arr[i]);
|
|
454
|
-
}
|
|
455
|
-
} catch (remove_error) {
|
|
456
|
-
this.log('error', `事件移除失败 [${space}:${key}]`, remove_error);
|
|
457
|
-
}
|
|
458
|
-
};
|
|
459
|
-
|
|
460
|
-
Eventer.prototype._autoCleanup = function (space, key) {
|
|
461
|
-
try {
|
|
462
|
-
if (this.config.auto_clean && this._dict[space] && this._dict[space][key] &&
|
|
463
|
-
this._dict[space][key].length === 0) {
|
|
464
|
-
delete this._dict[space][key];
|
|
465
|
-
if (this._dict[space] && Object.keys(this._dict[space]).length === 0) {
|
|
466
|
-
delete this._dict[space];
|
|
467
|
-
delete this._space[space];
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
} catch (cleanup_error) {
|
|
471
|
-
this.log('error', `自动清理失败 [${space}:${key}]`, cleanup_error);
|
|
472
|
-
}
|
|
473
|
-
};
|
|
474
|
-
|
|
475
|
-
Eventer.prototype._runAfterMiddleware = async function (ctx, start_time) {
|
|
476
|
-
try {
|
|
477
|
-
ctx.end_time = Date.now();
|
|
478
|
-
ctx.duration = ctx.end_time - start_time;
|
|
479
|
-
await this._runMiddleware('after', ctx);
|
|
480
|
-
} catch (error) {
|
|
481
|
-
this.log('error', `事件后置中间件执行失败 [${ctx.space}:${ctx.event}]`, error);
|
|
482
|
-
if (this.config.error_handler && typeof this.config.error_handler === 'function') {
|
|
483
|
-
this.config.error_handler(error, { type: 'middleware', stage: 'after', ctx });
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
};
|
|
487
|
-
|
|
488
|
-
Eventer.prototype._executeEventChain = async function (ctx, full_key, params) {
|
|
489
|
-
if (!ctx.cancelled && this.config.chain_enabled && this._chain[full_key]) {
|
|
490
|
-
try {
|
|
491
|
-
await this._triggerChain(full_key, params);
|
|
492
|
-
} catch (chain_error) {
|
|
493
|
-
this.log('error', `事件链执行失败 [${full_key}]`, chain_error);
|
|
494
|
-
if (this.config.error_handler && typeof this.config.error_handler === 'function') {
|
|
495
|
-
this.config.error_handler(chain_error, { type: 'chain', ctx });
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
};
|
|
500
|
-
|
|
501
|
-
Eventer.prototype._buildSafeResult = function (ctx) {
|
|
502
|
-
try {
|
|
503
|
-
return {
|
|
504
|
-
results: ctx.results || [],
|
|
505
|
-
cancelled: ctx.cancelled || false,
|
|
506
|
-
cancel: ctx.cancel || (() => { }),
|
|
507
|
-
race: ctx.race_result,
|
|
508
|
-
waterfall: ctx.results && ctx.results.length > 0 ? ctx.results[ctx.results.length - 1]
|
|
509
|
-
: undefined
|
|
510
|
-
};
|
|
511
|
-
} catch (return_error) {
|
|
512
|
-
this.log('error', `结果构造失败 [${ctx.full_event}]`, return_error);
|
|
513
|
-
return {
|
|
514
|
-
results: [],
|
|
515
|
-
cancelled: true,
|
|
516
|
-
cancel: () => { },
|
|
517
|
-
error: return_error
|
|
518
|
-
};
|
|
519
|
-
}
|
|
520
|
-
};
|
|
521
|
-
|
|
522
|
-
Eventer.prototype._execute = async function (key, options = {}, ...params) {
|
|
523
|
-
this._validateExec(key);
|
|
524
|
-
|
|
525
|
-
const { ctx, space, event_key, full_key, start_time } = this._createCtx(key, params);
|
|
526
|
-
|
|
527
|
-
if (this.isPaused(full_key)) {
|
|
528
|
-
return this._createPausedResult();
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
let list = this._dict[space] && this._dict[space][event_key];
|
|
532
|
-
const arr = [];
|
|
533
|
-
|
|
534
|
-
if (list && list.length > 0) {
|
|
535
|
-
await this._executeEventList({
|
|
536
|
-
list, params, ctx, full_key, arr, options, space, event_key, start_time
|
|
537
|
-
});
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
await this._executeEventChain(ctx, full_key, params);
|
|
541
|
-
return this._buildSafeResult(ctx);
|
|
542
|
-
};
|
|
543
|
-
|
|
544
|
-
/**
|
|
545
|
-
* 创建暂停状态的结果对象
|
|
546
|
-
* @returns {object} 暂停状态的结果
|
|
547
|
-
* @private
|
|
548
|
-
*/
|
|
549
|
-
Eventer.prototype._createPausedResult = function () {
|
|
550
|
-
return {
|
|
551
|
-
results: [],
|
|
552
|
-
cancelled: false,
|
|
553
|
-
paused: true,
|
|
554
|
-
/**
|
|
555
|
-
* 取消函数
|
|
556
|
-
*/
|
|
557
|
-
cancel: () => { }
|
|
558
|
-
};
|
|
559
|
-
};
|
|
560
|
-
|
|
561
|
-
/**
|
|
562
|
-
* 执行事件列表
|
|
563
|
-
* @param {object} config 配置参数
|
|
564
|
-
* @param {Array} config.list 事件列表
|
|
565
|
-
* @param {Array} config.params 参数
|
|
566
|
-
* @param {object} config.ctx 上下文
|
|
567
|
-
* @param {string} config.full_key 完整键名
|
|
568
|
-
* @param {Array} config.arr 数组
|
|
569
|
-
* @param {object} config.options 选项
|
|
570
|
-
* @param {string} config.space 命名空间
|
|
571
|
-
* @param {string} config.event_key 事件键
|
|
572
|
-
* @param {number} config.start_time 开始时间
|
|
573
|
-
* @param {string} config.strategy 执行策略,默认sequential
|
|
574
|
-
* @returns {object} 返回执行结果
|
|
575
|
-
* @private
|
|
576
|
-
*/
|
|
577
|
-
Eventer.prototype._executeEventList = async function (config) {
|
|
578
|
-
const { list, params, ctx, full_key, arr, options, space, event_key, start_time } = config;
|
|
579
|
-
|
|
580
|
-
this._initTaskList(full_key);
|
|
581
|
-
|
|
582
|
-
let cancelled = await this._runBeforeMiddleware(ctx, full_key);
|
|
583
|
-
if (cancelled) {
|
|
584
|
-
return {
|
|
585
|
-
results: [],
|
|
586
|
-
cancelled: true,
|
|
587
|
-
cancel: ctx.cancel
|
|
588
|
-
};
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
await this._executeStrategy({ list, params, ctx, full_key, arr, options });
|
|
592
|
-
|
|
593
|
-
this._cleanupTasks(full_key);
|
|
594
|
-
this._removeEvents(space, event_key, arr);
|
|
595
|
-
this._autoCleanup(space, event_key);
|
|
596
|
-
await this._runAfterMiddleware(ctx, start_time);
|
|
597
|
-
};
|
|
598
|
-
|
|
599
|
-
/**
|
|
600
|
-
* 顺序执行事件处理函数
|
|
601
|
-
* @param {object} config 配置参数
|
|
602
|
-
* @private
|
|
603
|
-
*/
|
|
604
|
-
Eventer.prototype._executeSequential = async function (config) {
|
|
605
|
-
const { list, params, ctx, full_key, arr } = config;
|
|
606
|
-
|
|
607
|
-
for (let i = 0; i < list.length && !ctx.cancelled; i++) {
|
|
608
|
-
let o = list[i];
|
|
609
|
-
ctx.executed++;
|
|
610
|
-
o.last_executed = Date.now();
|
|
611
|
-
|
|
612
|
-
// 创建并执行单个任务
|
|
613
|
-
await this._execSingleTask(o, params, ctx, { full_key, arr });
|
|
614
|
-
}
|
|
615
|
-
};
|
|
616
|
-
|
|
617
|
-
Eventer.prototype._execSingleTask = async function (o, params, ctx, options) {
|
|
618
|
-
const { full_key, arr } = options;
|
|
619
|
-
|
|
620
|
-
// 创建任务
|
|
621
|
-
let task = this._createTask(o, full_key);
|
|
622
|
-
|
|
623
|
-
try {
|
|
624
|
-
// 执行事件处理函数
|
|
625
|
-
let result = await o.func.apply(o, params);
|
|
626
|
-
|
|
627
|
-
// 处理成功结果
|
|
628
|
-
this._handleSuccessResult({ result, o, ctx, arr, task });
|
|
629
|
-
} catch (e) {
|
|
630
|
-
// 处理错误
|
|
631
|
-
this._handleSeqTaskError(e, o, ctx, task);
|
|
632
|
-
}
|
|
633
|
-
};
|
|
634
|
-
|
|
635
|
-
Eventer.prototype._createTask = function (o, full_key) {
|
|
636
|
-
let task_id = `${o.name}_${Date.now()}`;
|
|
637
|
-
let cancelled = false;
|
|
638
|
-
const task = {
|
|
639
|
-
id: task_id,
|
|
640
|
-
cancel: () => { cancelled = true; }
|
|
641
|
-
};
|
|
642
|
-
|
|
643
|
-
// 添加到进行中的任务列表(防御性处理重入调用导致 key 已被清理的情况)
|
|
644
|
-
let tasks = this._tasks.get(full_key);
|
|
645
|
-
if (!tasks) {
|
|
646
|
-
tasks = [];
|
|
647
|
-
this._tasks.set(full_key, tasks);
|
|
648
|
-
}
|
|
649
|
-
tasks.push(task);
|
|
650
|
-
|
|
651
|
-
return { task, tasks, cancelled };
|
|
652
|
-
};
|
|
653
|
-
|
|
654
|
-
Eventer.prototype._handleSuccessResult = function (config) {
|
|
655
|
-
const { result, o, ctx, arr, task } = config;
|
|
656
|
-
|
|
657
|
-
// 如果任务已取消,则不添加结果
|
|
658
|
-
if (!task.cancelled && !ctx.cancelled) {
|
|
659
|
-
ctx.results.push(result);
|
|
660
|
-
|
|
661
|
-
// 处理执行次数限制
|
|
662
|
-
if (o.times >= 0) {
|
|
663
|
-
o.times--;
|
|
664
|
-
if (o.times <= 0) {
|
|
665
|
-
arr.push(o.name);
|
|
666
|
-
}
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
// 从进行中的任务列表中移除
|
|
671
|
-
task.tasks.splice(task.tasks.indexOf(task.task), 1);
|
|
672
|
-
};
|
|
673
|
-
|
|
674
|
-
Eventer.prototype._handleSeqTaskError = function (e, o, ctx, task) {
|
|
675
|
-
ctx.error_count++;
|
|
676
|
-
this.log('error', `事件执行失败 [${ctx.space}:${ctx.event}] - ${o.name}`, e);
|
|
677
|
-
|
|
678
|
-
const error_result = {
|
|
679
|
-
_error: true,
|
|
680
|
-
error: e,
|
|
681
|
-
handler: o.name,
|
|
682
|
-
timestamp: Date.now()
|
|
683
|
-
};
|
|
684
|
-
|
|
685
|
-
ctx.results.push(error_result);
|
|
686
|
-
|
|
687
|
-
// 全局错误处理器
|
|
688
|
-
if (this.config.error_handler && typeof this.config.error_handler === 'function') {
|
|
689
|
-
this.config.error_handler(e, { type: 'handler', handler: o.name, ctx });
|
|
690
|
-
}
|
|
691
|
-
|
|
692
|
-
// 从进行中的任务列表中移除
|
|
693
|
-
task.tasks.splice(task.tasks.indexOf(task.task), 1);
|
|
694
|
-
};
|
|
695
|
-
|
|
696
|
-
/**
|
|
697
|
-
* 并行执行事件处理函数
|
|
698
|
-
* @param {object} config 配置参数
|
|
699
|
-
* @private
|
|
700
|
-
*/
|
|
701
|
-
Eventer.prototype._executeParallel = async function (config) {
|
|
702
|
-
const { list, params, ctx, full_key, arr } = config;
|
|
703
|
-
let concurrency = this._getConcurrency(params);
|
|
704
|
-
// eslint-disable-next-line mm_eslint/class-instance-name
|
|
705
|
-
const proc_results = new Array(list.length);
|
|
706
|
-
|
|
707
|
-
if (concurrency < Infinity) {
|
|
708
|
-
await this._executeBatches({
|
|
709
|
-
list, params, ctx, full_key, arr, concurrency, proc_results
|
|
710
|
-
});
|
|
711
|
-
} else {
|
|
712
|
-
await this._executeAllParallel({ list, params, ctx, full_key, arr, proc_results });
|
|
713
|
-
}
|
|
714
|
-
|
|
715
|
-
this._setResults(ctx, proc_results);
|
|
716
|
-
};
|
|
717
|
-
|
|
718
|
-
Eventer.prototype._getConcurrency = function (params) {
|
|
719
|
-
return params.options && typeof params.options.concurrency === 'number' ?
|
|
720
|
-
params.options.concurrency : Infinity;
|
|
721
|
-
};
|
|
722
|
-
|
|
723
|
-
Eventer.prototype._executeBatches = async function (config) {
|
|
724
|
-
const { list, params, ctx, full_key, arr, concurrency, proc_results } = config;
|
|
725
|
-
|
|
726
|
-
for (let i = 0; i < list.length && !ctx.cancelled; i += concurrency) {
|
|
727
|
-
let batch = list.slice(i, i + concurrency);
|
|
728
|
-
let batch_promises = batch.map((obj, batch_idx) => {
|
|
729
|
-
let global = i + batch_idx;
|
|
730
|
-
return this._executeSingleTask({
|
|
731
|
-
obj, params, ctx, full_key, arr, idx: global, proc_results
|
|
732
|
-
});
|
|
733
|
-
});
|
|
734
|
-
|
|
735
|
-
await Promise.allSettled(batch_promises);
|
|
736
|
-
}
|
|
737
|
-
};
|
|
738
|
-
|
|
739
|
-
Eventer.prototype._executeAllParallel = async function (config) {
|
|
740
|
-
const { list, params, ctx, full_key, arr, proc_results } = config;
|
|
741
|
-
|
|
742
|
-
let promises = list.map((obj, idx) => {
|
|
743
|
-
return this._executeSingleTask({ obj, params, ctx, full_key, arr, idx, proc_results });
|
|
744
|
-
});
|
|
745
|
-
|
|
746
|
-
await Promise.allSettled(promises);
|
|
747
|
-
};
|
|
748
|
-
|
|
749
|
-
Eventer.prototype._setResults = function (ctx, proc_results) {
|
|
750
|
-
ctx.results = proc_results.filter(result => result !== undefined);
|
|
751
|
-
};
|
|
752
|
-
|
|
753
|
-
/**
|
|
754
|
-
* 瀑布流执行事件处理函数
|
|
755
|
-
* @param {object} config 配置参数
|
|
756
|
-
* @private
|
|
757
|
-
*/
|
|
758
|
-
Eventer.prototype._executeWaterfall = async function (config) {
|
|
759
|
-
const { list, params, ctx, full_key, arr, initial_value } = config;
|
|
760
|
-
let wate_value = this._getInitialValue(params, initial_value);
|
|
761
|
-
|
|
762
|
-
for (let i = 0; i < list.length && !ctx.cancelled; i++) {
|
|
763
|
-
let obj = list[i];
|
|
764
|
-
ctx.executed++;
|
|
765
|
-
obj.last_executed = Date.now();
|
|
766
|
-
|
|
767
|
-
let task = this._createWaterfallTask(obj, full_key);
|
|
768
|
-
wate_value = await this._execWaterfallStep({
|
|
769
|
-
obj, params, ctx, arr, task, wate_value
|
|
770
|
-
});
|
|
771
|
-
}
|
|
772
|
-
};
|
|
773
|
-
|
|
774
|
-
Eventer.prototype._getInitialValue = function (params, initial_value) {
|
|
775
|
-
return initial_value !== undefined ? initial_value : (params.length > 0 ? params[0] : undefined);
|
|
776
|
-
};
|
|
777
|
-
|
|
778
|
-
Eventer.prototype._createWaterfallTask = function (obj, full_key) {
|
|
779
|
-
let task_id = `${obj.name}_${Date.now()}`;
|
|
780
|
-
let cancelled = false;
|
|
781
|
-
const task = {
|
|
782
|
-
id: task_id,
|
|
783
|
-
cancel: () => { cancelled = true; }
|
|
784
|
-
};
|
|
785
|
-
|
|
786
|
-
let tasks = this._tasks.get(full_key);
|
|
787
|
-
if (!tasks) {
|
|
788
|
-
tasks = [];
|
|
789
|
-
this._tasks.set(full_key, tasks);
|
|
790
|
-
}
|
|
791
|
-
tasks.push(task);
|
|
792
|
-
|
|
793
|
-
return { task, tasks, cancelled };
|
|
794
|
-
};
|
|
795
|
-
|
|
796
|
-
Eventer.prototype._execWaterfallStep = async function (config) {
|
|
797
|
-
const { obj, params, ctx, arr, task, wate_value } = config;
|
|
798
|
-
try {
|
|
799
|
-
let result = await obj.func.apply(obj, [wate_value, ...params.slice(1)]);
|
|
800
|
-
this._handleWfSuccess({ result, obj, ctx, arr, task });
|
|
801
|
-
return result;
|
|
802
|
-
} catch (e) {
|
|
803
|
-
this._handleWfError({ e, obj, ctx, task });
|
|
804
|
-
return wate_value;
|
|
805
|
-
}
|
|
806
|
-
};
|
|
807
|
-
|
|
808
|
-
Eventer.prototype._handleWfSuccess = function (config) {
|
|
809
|
-
const { result, obj, ctx, arr, task } = config;
|
|
810
|
-
if (!task.cancelled && !ctx.cancelled) {
|
|
811
|
-
ctx.results.push(result);
|
|
812
|
-
this._handleTimesLimit(obj, arr);
|
|
813
|
-
}
|
|
814
|
-
this._removeTask(task);
|
|
815
|
-
};
|
|
816
|
-
|
|
817
|
-
Eventer.prototype._handleWfError = function (config) {
|
|
818
|
-
const { e, obj, ctx, task } = config;
|
|
819
|
-
ctx.error_count++;
|
|
820
|
-
this.log('error', `事件执行失败 [${ctx.space}:${ctx.event}] - ${obj.name}`, e);
|
|
821
|
-
|
|
822
|
-
const error_result = {
|
|
823
|
-
_error: true,
|
|
824
|
-
error: e,
|
|
825
|
-
handler: obj.name,
|
|
826
|
-
timestamp: Date.now()
|
|
827
|
-
};
|
|
828
|
-
|
|
829
|
-
ctx.results.push(error_result);
|
|
830
|
-
this._callErrorHandler(e, obj, ctx);
|
|
831
|
-
this._removeTask(task);
|
|
832
|
-
};
|
|
833
|
-
|
|
834
|
-
Eventer.prototype._handleTimesLimit = function (obj, arr) {
|
|
835
|
-
if (obj.times >= 0) {
|
|
836
|
-
obj.times--;
|
|
837
|
-
if (obj.times <= 0) {
|
|
838
|
-
arr.push(obj.name);
|
|
839
|
-
}
|
|
840
|
-
}
|
|
841
|
-
};
|
|
842
|
-
|
|
843
|
-
Eventer.prototype._removeTask = function (task) {
|
|
844
|
-
task.tasks.splice(task.tasks.indexOf(task.task), 1);
|
|
845
|
-
};
|
|
846
|
-
|
|
847
|
-
Eventer.prototype._callErrorHandler = function (e, obj, ctx) {
|
|
848
|
-
if (this.config.error_handler && typeof this.config.error_handler === 'function') {
|
|
849
|
-
this.config.error_handler(e, { type: 'handler', handler: obj.name, ctx });
|
|
850
|
-
}
|
|
851
|
-
};
|
|
852
|
-
|
|
853
|
-
/**
|
|
854
|
-
* 竞争执行模式 - 返回第一个完成的结果
|
|
855
|
-
* @param {object} config 配置参数
|
|
856
|
-
* @param {Array} config.list 事件列表
|
|
857
|
-
* @param {Array} config.params 参数
|
|
858
|
-
* @param {object} config.ctx 上下文
|
|
859
|
-
* @param {string} config.strategy 执行策略
|
|
860
|
-
* @returns {Promise<object>} 返回包含results和cancel方法的对象
|
|
861
|
-
* @private
|
|
862
|
-
*/
|
|
863
|
-
Eventer.prototype._executeRace = async function (config) {
|
|
864
|
-
const { list, params, ctx, full_key, arr } = config;
|
|
865
|
-
let promises = this._createRacePromises({ list, params, ctx, full_key, arr });
|
|
866
|
-
|
|
867
|
-
return await this._runRace(promises);
|
|
868
|
-
};
|
|
869
|
-
|
|
870
|
-
Eventer.prototype._createRacePromises = function (config) {
|
|
871
|
-
const { list, params, ctx, full_key, arr } = config;
|
|
872
|
-
const promises = [];
|
|
873
|
-
|
|
874
|
-
for (let i = 0; i < list.length && !ctx.cancelled; i++) {
|
|
875
|
-
let obj = list[i];
|
|
876
|
-
ctx.executed++;
|
|
877
|
-
obj.last_executed = Date.now();
|
|
878
|
-
|
|
879
|
-
let promise = this._createRacePromise({ obj, params, ctx, full_key, arr });
|
|
880
|
-
promises.push(promise);
|
|
881
|
-
}
|
|
882
|
-
|
|
883
|
-
return promises;
|
|
884
|
-
};
|
|
885
|
-
|
|
886
|
-
Eventer.prototype._createRacePromise = function (config) {
|
|
887
|
-
const { obj, params, ctx, full_key, arr } = config;
|
|
888
|
-
let task = this._createRaceTask(obj, full_key);
|
|
889
|
-
|
|
890
|
-
return (async () => {
|
|
891
|
-
try {
|
|
892
|
-
let result = await obj.func.apply(obj, params);
|
|
893
|
-
return this._handleRaceSuccess({ result, obj, ctx, arr, task });
|
|
894
|
-
} catch (e) {
|
|
895
|
-
return this._handleRaceError(e, obj, ctx, task);
|
|
896
|
-
} finally {
|
|
897
|
-
this._removeTask(task);
|
|
898
|
-
}
|
|
899
|
-
})();
|
|
900
|
-
};
|
|
901
|
-
|
|
902
|
-
Eventer.prototype._createRaceTask = function (obj, full_key) {
|
|
903
|
-
let task_id = `${obj.name}_${Date.now()}`;
|
|
904
|
-
let cancelled = false;
|
|
905
|
-
const task = {
|
|
906
|
-
id: task_id,
|
|
907
|
-
cancel: () => { cancelled = true; }
|
|
908
|
-
};
|
|
909
|
-
|
|
910
|
-
let tasks = this._tasks.get(full_key);
|
|
911
|
-
if (!tasks) {
|
|
912
|
-
tasks = [];
|
|
913
|
-
this._tasks.set(full_key, tasks);
|
|
914
|
-
}
|
|
915
|
-
tasks.push(task);
|
|
916
|
-
|
|
917
|
-
return { task, tasks, cancelled };
|
|
918
|
-
};
|
|
919
|
-
|
|
920
|
-
Eventer.prototype._handleRaceSuccess = function (config) {
|
|
921
|
-
const { result, obj, ctx, arr, task } = config;
|
|
922
|
-
|
|
923
|
-
if (!task.cancelled && !ctx.cancelled) {
|
|
924
|
-
ctx.results.push(result);
|
|
925
|
-
this._handleTimesLimit(obj, arr);
|
|
926
|
-
return { success: true, result, handler: obj.name };
|
|
927
|
-
}
|
|
928
|
-
return { success: false, cancelled: true };
|
|
929
|
-
};
|
|
930
|
-
|
|
931
|
-
Eventer.prototype._handleRaceError = function (e, obj, ctx, task) {
|
|
932
|
-
ctx.error_count++;
|
|
933
|
-
this.log('error', `事件执行失败 [${ctx.space}:${ctx.event}] - ${obj.name}`, e);
|
|
934
|
-
|
|
935
|
-
const error_result = {
|
|
936
|
-
_error: true,
|
|
937
|
-
error: e,
|
|
938
|
-
handler: obj.name,
|
|
939
|
-
timestamp: Date.now()
|
|
940
|
-
};
|
|
941
|
-
|
|
942
|
-
ctx.results.push(error_result);
|
|
943
|
-
this._callErrorHandler(e, obj, ctx);
|
|
944
|
-
|
|
945
|
-
return { success: false, error: e, handler: obj.name };
|
|
946
|
-
};
|
|
947
|
-
|
|
948
|
-
Eventer.prototype._runRace = async function (promises) {
|
|
949
|
-
if (promises.length > 0) {
|
|
950
|
-
let race = await Promise.race(promises);
|
|
951
|
-
return race;
|
|
952
|
-
}
|
|
953
|
-
return null;
|
|
954
|
-
};
|
|
955
|
-
|
|
956
|
-
/**
|
|
957
|
-
* 执行单个任务(并行执行时使用)
|
|
958
|
-
* @param {object} config 配置参数
|
|
959
|
-
* @private
|
|
960
|
-
*/
|
|
961
|
-
Eventer.prototype._executeSingleTask = async function (config) {
|
|
962
|
-
const { obj, params, ctx, full_key, arr, idx, proc_results } = config;
|
|
963
|
-
obj.last_executed = Date.now();
|
|
964
|
-
|
|
965
|
-
// 创建任务
|
|
966
|
-
let task_info = this._createParallelTask(obj, full_key);
|
|
967
|
-
|
|
968
|
-
try {
|
|
969
|
-
let result = await obj.func.apply(obj, params);
|
|
970
|
-
this._handleTaskSuccess({ result, obj, ctx, arr, idx, proc_results, task_info });
|
|
971
|
-
} catch (err) {
|
|
972
|
-
this._handleTaskError({ err, obj, ctx, idx, proc_results, task_info });
|
|
973
|
-
}
|
|
974
|
-
};
|
|
975
|
-
|
|
976
|
-
Eventer.prototype._createParallelTask = function (obj, full_key) {
|
|
977
|
-
let task_id = `${obj.name}_${Date.now()}`;
|
|
978
|
-
let cancelled = false;
|
|
979
|
-
const task = {
|
|
980
|
-
id: task_id,
|
|
981
|
-
cancel: () => { cancelled = true; }
|
|
982
|
-
};
|
|
983
|
-
|
|
984
|
-
// 添加到进行中的任务列表(防御性处理重入调用导致 key 已被清理的情况)
|
|
985
|
-
let tasks = this._tasks.get(full_key);
|
|
986
|
-
if (!tasks) {
|
|
987
|
-
tasks = [];
|
|
988
|
-
this._tasks.set(full_key, tasks);
|
|
989
|
-
}
|
|
990
|
-
tasks.push(task);
|
|
991
|
-
|
|
992
|
-
return { task, tasks, cancelled };
|
|
993
|
-
};
|
|
994
|
-
|
|
995
|
-
Eventer.prototype._handleTaskSuccess = function (config) {
|
|
996
|
-
const { result, obj, ctx, arr, idx, proc_results, task_info } = config;
|
|
997
|
-
|
|
998
|
-
// 从进行中的任务列表中移除
|
|
999
|
-
task_info.tasks.splice(task_info.tasks.indexOf(task_info.task), 1);
|
|
1000
|
-
|
|
1001
|
-
if (!task_info.cancelled && !ctx.cancelled) {
|
|
1002
|
-
proc_results[idx] = result;
|
|
1003
|
-
|
|
1004
|
-
// 处理执行次数限制
|
|
1005
|
-
if (obj.times >= 0) {
|
|
1006
|
-
obj.times--;
|
|
1007
|
-
if (obj.times <= 0) {
|
|
1008
|
-
arr.push(obj.name);
|
|
1009
|
-
}
|
|
1010
|
-
}
|
|
1011
|
-
}
|
|
1012
|
-
};
|
|
1013
|
-
|
|
1014
|
-
Eventer.prototype._handleTaskError = function (config) {
|
|
1015
|
-
const { err, obj, ctx, idx, proc_results, task_info } = config;
|
|
1016
|
-
|
|
1017
|
-
// 从进行中的任务列表中移除
|
|
1018
|
-
task_info.tasks.splice(task_info.tasks.indexOf(task_info.task), 1);
|
|
1019
|
-
|
|
1020
|
-
if (!task_info.cancelled && !ctx.cancelled) {
|
|
1021
|
-
const error_result = {
|
|
1022
|
-
_error: true,
|
|
1023
|
-
error: err,
|
|
1024
|
-
handler: obj.name,
|
|
1025
|
-
timestamp: Date.now()
|
|
1026
|
-
};
|
|
1027
|
-
proc_results[idx] = error_result;
|
|
1028
|
-
|
|
1029
|
-
// 全局错误处理器
|
|
1030
|
-
if (this.config.error_handler && typeof this.config.error_handler === 'function') {
|
|
1031
|
-
this.config.error_handler(err, { type: 'handler', handler: obj.name, ctx });
|
|
1032
|
-
}
|
|
1033
|
-
}
|
|
1034
|
-
};
|
|
1035
|
-
|
|
1036
|
-
/**
|
|
1037
|
-
* 执行事件(支持中间件和命名空间)
|
|
1038
|
-
* @param {string} key 事件关键字,支持space:key格式
|
|
1039
|
-
* @param {object} params 传递参数
|
|
1040
|
-
* @returns {Promise<object>} 返回包含results和cancel方法的对象
|
|
1041
|
-
*/
|
|
1042
|
-
Eventer.prototype.run = async function (key, ...params) {
|
|
1043
|
-
return this._execute(key, { exec_mode: 'sequential' }, ...params);
|
|
1044
|
-
};
|
|
1045
|
-
|
|
1046
|
-
/**
|
|
1047
|
-
* 触发事件
|
|
1048
|
-
* @param {string} key 事件关键,支持space:key格式
|
|
1049
|
-
* @param {object} params 传递参数
|
|
1050
|
-
* @returns {Promise<object>} 返回包含results和cancel方法的对象
|
|
1051
|
-
*/
|
|
1052
|
-
Eventer.prototype.emit = function (key, ...params) {
|
|
1053
|
-
// 内部调用 _execute 方法,但不等待结果
|
|
1054
|
-
try {
|
|
1055
|
-
let result = this._execute(key, { exec_mode: 'sequential' }, ...params);
|
|
1056
|
-
result.catch(e => this.log('error', '事件异步执行失败:', e));
|
|
1057
|
-
return {
|
|
1058
|
-
...result,
|
|
1059
|
-
cancel: () => {
|
|
1060
|
-
try {
|
|
1061
|
-
return result.then(r => r && typeof r.cancel === 'function' && r.cancel());
|
|
1062
|
-
} catch (cancel_error) {
|
|
1063
|
-
this.log('error', `事件取消失败 [${key}]`, cancel_error);
|
|
1064
|
-
return Promise.resolve();
|
|
1065
|
-
}
|
|
1066
|
-
}
|
|
1067
|
-
};
|
|
1068
|
-
} catch (error) {
|
|
1069
|
-
this.log('error', `事件触发失败 [${key}]`, error);
|
|
1070
|
-
// 返回一个安全的默认结果
|
|
1071
|
-
return {
|
|
1072
|
-
results: [],
|
|
1073
|
-
cancelled: false,
|
|
1074
|
-
cancel: () => { },
|
|
1075
|
-
error: error
|
|
1076
|
-
};
|
|
1077
|
-
}
|
|
1078
|
-
};
|
|
1079
|
-
|
|
1080
|
-
/**
|
|
1081
|
-
* 异步触发事件,按顺序执行等待完成
|
|
1082
|
-
* @param {string} key 事件关键字,支持space:key格式
|
|
1083
|
-
* @param {...any} args 事件参数
|
|
1084
|
-
* @returns {Promise} - 事件触发结果
|
|
1085
|
-
*/
|
|
1086
|
-
Eventer.prototype.emitWait = async function (key, ...args) {
|
|
1087
|
-
try {
|
|
1088
|
-
let result = await this._execute(key, { exec_mode: 'sequential' }, ...args);
|
|
1089
|
-
return result.results || [];
|
|
1090
|
-
} catch (error) {
|
|
1091
|
-
this.log('error', `等待事件触发失败 [${key}]`, error);
|
|
1092
|
-
return [];
|
|
1093
|
-
}
|
|
1094
|
-
};
|
|
1095
|
-
|
|
1096
|
-
/**
|
|
1097
|
-
* 异步触发事件,并发执行不等待
|
|
1098
|
-
* @param {string} key 事件关键字,支持space:key格式
|
|
1099
|
-
* @param {...any} args 事件参数
|
|
1100
|
-
* @returns {boolean} - 是否有监听者
|
|
1101
|
-
*/
|
|
1102
|
-
Eventer.prototype.emitAsync = async function (key, ...args) {
|
|
1103
|
-
try {
|
|
1104
|
-
return this._execAsync(key, args);
|
|
1105
|
-
} catch (global_error) {
|
|
1106
|
-
this.log('error', `异步事件触发失败 [${key}]`, global_error);
|
|
1107
|
-
return false;
|
|
1108
|
-
}
|
|
1109
|
-
};
|
|
1110
|
-
|
|
1111
|
-
Eventer.prototype._execAsync = function (key, args) {
|
|
1112
|
-
// 解析命名空间
|
|
1113
|
-
let parsed = this._parseKey(key);
|
|
1114
|
-
let space = parsed.space;
|
|
1115
|
-
let event_key = parsed.key;
|
|
1116
|
-
let full_key = `${space}:${event_key}`;
|
|
1117
|
-
|
|
1118
|
-
// 获取事件列表
|
|
1119
|
-
let list = this._dict[space] && this._dict[space][event_key];
|
|
1120
|
-
|
|
1121
|
-
if (!list || list.length === 0) {
|
|
1122
|
-
return false;
|
|
1123
|
-
}
|
|
1124
|
-
|
|
1125
|
-
// 立即启动所有监听器,但不等待
|
|
1126
|
-
list.forEach(handler => {
|
|
1127
|
-
this._executeAsyncHandler(handler, args, full_key);
|
|
1128
|
-
});
|
|
1129
|
-
|
|
1130
|
-
return true;
|
|
1131
|
-
};
|
|
1132
|
-
|
|
1133
|
-
Eventer.prototype._executeAsyncHandler = function (handler, args, full_key) {
|
|
1134
|
-
try {
|
|
1135
|
-
// 使用 Promise.resolve 确保异步执行
|
|
1136
|
-
Promise.resolve(handler.func(...args))
|
|
1137
|
-
.catch(error => {
|
|
1138
|
-
this._handleAsyncError(error, full_key, args);
|
|
1139
|
-
});
|
|
1140
|
-
} catch (sync_error) {
|
|
1141
|
-
this._handleSyncError(sync_error, full_key, args);
|
|
1142
|
-
}
|
|
1143
|
-
};
|
|
1144
|
-
|
|
1145
|
-
Eventer.prototype._handleAsyncError = function (error, full_key, args) {
|
|
1146
|
-
// 错误处理 - 记录但不抛出
|
|
1147
|
-
this.log('error', `异步监听器错误 [${full_key}]:`, error);
|
|
1148
|
-
try {
|
|
1149
|
-
this.emit('async:error', error, full_key, args);
|
|
1150
|
-
} catch (error) {
|
|
1151
|
-
this.log('error', '错误事件触发失败 [async:error]', error);
|
|
1152
|
-
}
|
|
1153
|
-
};
|
|
1154
|
-
|
|
1155
|
-
Eventer.prototype._handleSyncError = function (sync_error, full_key, args) {
|
|
1156
|
-
// 同步错误处理
|
|
1157
|
-
this.log('error', `同步监听器错误 [${full_key}]:`, sync_error);
|
|
1158
|
-
try {
|
|
1159
|
-
this.emit('sync:error', sync_error, full_key, args);
|
|
1160
|
-
} catch (error) {
|
|
1161
|
-
this.log('error', '错误事件触发失败 [sync:error]', error);
|
|
1162
|
-
}
|
|
1163
|
-
};
|
|
1164
|
-
|
|
1165
|
-
/**
|
|
1166
|
-
* 异步触发事件,并发执行等待完成
|
|
1167
|
-
* @param {string} key 事件关键字,支持space:key格式
|
|
1168
|
-
* @param {...any} args 事件参数
|
|
1169
|
-
* @returns {Promise<Array>} - 所有监听器的执行结果
|
|
1170
|
-
*/
|
|
1171
|
-
Eventer.prototype.emitAll = async function (key, ...args) {
|
|
1172
|
-
try {
|
|
1173
|
-
let result = await this._execute(key, { exec_mode: 'parallel' }, ...args);
|
|
1174
|
-
return result.results || [];
|
|
1175
|
-
} catch (error) {
|
|
1176
|
-
this.log('error', `并发事件触发失败 [${key}]`, error);
|
|
1177
|
-
return [];
|
|
1178
|
-
}
|
|
1179
|
-
};
|
|
1180
|
-
|
|
1181
|
-
/**
|
|
1182
|
-
* 异步触发事件,竞争执行
|
|
1183
|
-
* @param {string} key 事件关键字,支持space:key格式
|
|
1184
|
-
* @param {...any} args 事件参数
|
|
1185
|
-
* @returns {Promise} - 第一个完成的结果
|
|
1186
|
-
*/
|
|
1187
|
-
Eventer.prototype.emitRace = async function (key, ...args) {
|
|
1188
|
-
try {
|
|
1189
|
-
let result = await this._execute(key, { exec_mode: 'race' }, ...args);
|
|
1190
|
-
return result.race || null;
|
|
1191
|
-
} catch (error) {
|
|
1192
|
-
this.log('error', `竞争事件触发失败 [${key}]`, error);
|
|
1193
|
-
return null;
|
|
1194
|
-
}
|
|
1195
|
-
};
|
|
1196
|
-
|
|
1197
|
-
/**
|
|
1198
|
-
* 异步触发事件,返回第一个有返回值的结果(不阻塞其他监听器)
|
|
1199
|
-
* @param {string} key 事件关键字,支持space:key格式
|
|
1200
|
-
* @param {...any} args 事件参数
|
|
1201
|
-
* @returns {Promise} - 第一个有返回值(非 undefined)的监听器结果
|
|
1202
|
-
* 所有监听器并行执行,返回第一个有返回值(非 undefined)的结果,返回 undefined 的监听器被跳过,其他监听器继续在后台执行不受影响
|
|
1203
|
-
*/
|
|
1204
|
-
Eventer.prototype.emitFirst = async function (key, ...args) {
|
|
1205
|
-
try {
|
|
1206
|
-
let parsed = this._parseKey(key);
|
|
1207
|
-
let space = parsed.space;
|
|
1208
|
-
let event_key = parsed.key;
|
|
1209
|
-
|
|
1210
|
-
let list = this._dict[space] && this._dict[space][event_key];
|
|
1211
|
-
if (!list || list.length === 0) {
|
|
1212
|
-
return undefined;
|
|
1213
|
-
}
|
|
1214
|
-
|
|
1215
|
-
return await new Promise(resolve => {
|
|
1216
|
-
let settled = false;
|
|
1217
|
-
let pending = list.length;
|
|
1218
|
-
|
|
1219
|
-
for (let handler of list) {
|
|
1220
|
-
Promise.resolve(handler.func(...args)).then(result => {
|
|
1221
|
-
if (!settled && result !== undefined) {
|
|
1222
|
-
settled = true;
|
|
1223
|
-
resolve(result);
|
|
1224
|
-
}
|
|
1225
|
-
pending--;
|
|
1226
|
-
if (pending === 0 && !settled) {
|
|
1227
|
-
resolve(undefined);
|
|
1228
|
-
}
|
|
1229
|
-
}).catch(() => {
|
|
1230
|
-
pending--;
|
|
1231
|
-
if (pending === 0 && !settled) {
|
|
1232
|
-
resolve(undefined);
|
|
1233
|
-
}
|
|
1234
|
-
});
|
|
1235
|
-
}
|
|
1236
|
-
});
|
|
1237
|
-
} catch (error) {
|
|
1238
|
-
this.log('error', `首个结果事件触发失败 [${key}]`, error);
|
|
1239
|
-
return undefined;
|
|
1240
|
-
}
|
|
1241
|
-
};
|
|
1242
|
-
|
|
1243
|
-
/**
|
|
1244
|
-
* 异步触发事件,瀑布流执行
|
|
1245
|
-
* @param {string} key 事件关键字,支持space:key格式
|
|
1246
|
-
* @param {*} value 初始值
|
|
1247
|
-
* @param {...any} args 事件参数
|
|
1248
|
-
* @returns {Promise} - 最后一个事件监听者的结果
|
|
1249
|
-
*/
|
|
1250
|
-
Eventer.prototype.emitWaterfall = async function (key, value, ...args) {
|
|
1251
|
-
try {
|
|
1252
|
-
let result = await this._execute(key, {
|
|
1253
|
-
exec_mode: 'waterfall',
|
|
1254
|
-
initial_value: value
|
|
1255
|
-
}, ...args);
|
|
1256
|
-
return result.waterfall || value;
|
|
1257
|
-
} catch (error) {
|
|
1258
|
-
this.log('error', `瀑布流事件触发失败 [${key}]`, error);
|
|
1259
|
-
return value;
|
|
1260
|
-
}
|
|
1261
|
-
};
|
|
1262
|
-
|
|
1263
|
-
/**
|
|
1264
|
-
* 确保命名空间在映射中
|
|
1265
|
-
* @private
|
|
1266
|
-
* @param {string} name 命名空间名称
|
|
1267
|
-
*/
|
|
1268
|
-
Eventer.prototype._ensureNs = function (name) {
|
|
1269
|
-
if (!this._space[name]) {
|
|
1270
|
-
this._space[name] = true;
|
|
1271
|
-
}
|
|
1272
|
-
};
|
|
1273
|
-
|
|
1274
|
-
/**
|
|
1275
|
-
* 执行单个命名空间的事件处理函数
|
|
1276
|
-
* @private
|
|
1277
|
-
* @param {string} name 命名空间名称
|
|
1278
|
-
* @param {string} key 事件关键字
|
|
1279
|
-
* @param {Array} params 事件参数
|
|
1280
|
-
* @returns {object} 包含结果和需要移除的事件名称的对象
|
|
1281
|
-
*/
|
|
1282
|
-
Eventer.prototype._execNsEvents = async function (name, key, params) {
|
|
1283
|
-
let list = this._dict[name][key];
|
|
1284
|
-
const name_results = [];
|
|
1285
|
-
const arr = []; // 存储需要移除的事件
|
|
1286
|
-
|
|
1287
|
-
// 执行事件处理函数
|
|
1288
|
-
for (let i = 0; i < list.length; i++) {
|
|
1289
|
-
try {
|
|
1290
|
-
let obj = list[i];
|
|
1291
|
-
// 执行事件处理函数
|
|
1292
|
-
let result = await obj.func.apply(obj, params);
|
|
1293
|
-
name_results.push(result);
|
|
1294
|
-
|
|
1295
|
-
// 处理执行次数限制
|
|
1296
|
-
if (obj.times >= 0) {
|
|
1297
|
-
obj.times--;
|
|
1298
|
-
if (obj.times <= 0) {
|
|
1299
|
-
arr.push(obj.name);
|
|
1300
|
-
}
|
|
1301
|
-
}
|
|
1302
|
-
} catch (e) {
|
|
1303
|
-
// 记录错误但不中断执行
|
|
1304
|
-
this.log('error', `事件执行失败 [${name}:${key}] - ${list[i].name}`, e);
|
|
1305
|
-
name_results.push({
|
|
1306
|
-
_error: true,
|
|
1307
|
-
error: e,
|
|
1308
|
-
handler: list[i].name
|
|
1309
|
-
});
|
|
1310
|
-
}
|
|
1311
|
-
}
|
|
1312
|
-
|
|
1313
|
-
return { name_results, arr };
|
|
1314
|
-
};
|
|
1315
|
-
|
|
1316
|
-
/**
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
Eventer.prototype.
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
}
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
//
|
|
1359
|
-
|
|
1360
|
-
events.
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
}
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
}
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
}
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
}
|
|
1451
|
-
|
|
1452
|
-
//
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
}
|
|
1548
|
-
|
|
1549
|
-
//
|
|
1550
|
-
this.
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
this.
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
if (
|
|
1560
|
-
this.
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
}
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
}
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
}
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
//
|
|
1670
|
-
this.
|
|
1671
|
-
|
|
1672
|
-
//
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
};
|
|
1683
|
-
|
|
1684
|
-
Eventer.prototype.
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
};
|
|
1694
|
-
|
|
1695
|
-
Eventer.prototype.
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
}
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
}
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
if (
|
|
1764
|
-
|
|
1765
|
-
}
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
//
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
}
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
*
|
|
1813
|
-
* @param {string}
|
|
1814
|
-
* @param {
|
|
1815
|
-
* @returns {Promise<
|
|
1816
|
-
*/
|
|
1817
|
-
Eventer.prototype.
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
};
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
*
|
|
1831
|
-
* @param {string} key
|
|
1832
|
-
* @param {
|
|
1833
|
-
* @returns {Promise<
|
|
1834
|
-
*/
|
|
1835
|
-
Eventer.prototype.
|
|
1836
|
-
//
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
}
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
Eventer.prototype.
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
}
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
Eventer.prototype.
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
};
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
*
|
|
2049
|
-
* @
|
|
2050
|
-
* @
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
}
|
|
2089
|
-
}
|
|
2090
|
-
};
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
*
|
|
2095
|
-
* @param {
|
|
2096
|
-
* @
|
|
2097
|
-
*/
|
|
2098
|
-
Eventer.prototype.
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
}
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
}
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
}
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
}
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
this.
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
}
|
|
2258
|
-
|
|
2259
|
-
Eventer.prototype.
|
|
2260
|
-
if (this.
|
|
2261
|
-
this.log('warn',
|
|
2262
|
-
return false;
|
|
2263
|
-
}
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
let parsed = this._parseKey(key);
|
|
2296
|
-
let space = parsed.space;
|
|
2297
|
-
let event_key = parsed.key;
|
|
2298
|
-
let full_key = `${space}:${event_key}`;
|
|
2299
|
-
|
|
2300
|
-
if (key) {
|
|
2301
|
-
return this._resumeEvent(full_key);
|
|
2302
|
-
} else {
|
|
2303
|
-
return this._resumeNamespace(space);
|
|
2304
|
-
}
|
|
2305
|
-
};
|
|
2306
|
-
|
|
2307
|
-
Eventer.prototype._resumeGlobal = function () {
|
|
2308
|
-
if (!this._paused_global) {
|
|
2309
|
-
this.log('warn', '事件总线未处于全局暂停状态');
|
|
2310
|
-
return false;
|
|
2311
|
-
}
|
|
2312
|
-
this._paused_global = false;
|
|
2313
|
-
this.log('info', '事件总线已恢复运行');
|
|
2314
|
-
return true;
|
|
2315
|
-
};
|
|
2316
|
-
|
|
2317
|
-
Eventer.prototype._resumeEvent = function (full_key) {
|
|
2318
|
-
if (!this._paused.has(full_key)) {
|
|
2319
|
-
this.log('warn', `事件 '${full_key}' 未处于暂停状态`);
|
|
2320
|
-
return false;
|
|
2321
|
-
}
|
|
2322
|
-
this._paused.delete(full_key);
|
|
2323
|
-
this.log('info', `事件 '${full_key}' 已恢复`);
|
|
2324
|
-
return true;
|
|
2325
|
-
};
|
|
2326
|
-
|
|
2327
|
-
Eventer.prototype._resumeNamespace = function (space) {
|
|
2328
|
-
if (!this._paused_space.has(space)) {
|
|
2329
|
-
this.log('warn', `命名空间 '${space}' 未处于暂停状态`);
|
|
2330
|
-
return false;
|
|
2331
|
-
}
|
|
2332
|
-
this._paused_space.delete(space);
|
|
2333
|
-
this.log('info', `命名空间 '${space}' 已恢复`);
|
|
2334
|
-
return true;
|
|
2335
|
-
};
|
|
2336
|
-
|
|
2337
|
-
/**
|
|
2338
|
-
* 检查事件是否被暂停
|
|
2339
|
-
* @param {string} key 事件关键字,支持space:key格式
|
|
2340
|
-
* @returns {boolean} 是否被暂停
|
|
2341
|
-
*/
|
|
2342
|
-
Eventer.prototype.isPaused = function (key) {
|
|
2343
|
-
if (!this.config.pause_enabled) {
|
|
2344
|
-
return false;
|
|
2345
|
-
}
|
|
2346
|
-
|
|
2347
|
-
// 全局暂停检查
|
|
2348
|
-
if (this._paused_global) {
|
|
2349
|
-
return true;
|
|
2350
|
-
}
|
|
2351
|
-
|
|
2352
|
-
// 解析关键字
|
|
2353
|
-
let parsed = this._parseKey(key);
|
|
2354
|
-
let space = parsed.space;
|
|
2355
|
-
let event_key = parsed.key;
|
|
2356
|
-
let full_key = `${space}:${event_key}`;
|
|
2357
|
-
|
|
2358
|
-
// 命名空间暂停检查
|
|
2359
|
-
if (this._paused_space.has(space)) {
|
|
2360
|
-
return true;
|
|
2361
|
-
}
|
|
2362
|
-
|
|
2363
|
-
// 单个事件暂停检查
|
|
2364
|
-
if (this._paused.has(full_key)) {
|
|
2365
|
-
return true;
|
|
2366
|
-
}
|
|
2367
|
-
|
|
2368
|
-
return false;
|
|
2369
|
-
};
|
|
2370
|
-
|
|
2371
|
-
/**
|
|
2372
|
-
* 获取所有暂停的事件和命名空间
|
|
2373
|
-
* @returns {object} 暂停状态信息
|
|
2374
|
-
*/
|
|
2375
|
-
Eventer.prototype.getPausedStatus = function () {
|
|
2376
|
-
return {
|
|
2377
|
-
global_paused: this._paused_global,
|
|
2378
|
-
paused_events: Array.from(this._paused),
|
|
2379
|
-
paused_spaces: Array.from(this._paused_space)
|
|
2380
|
-
};
|
|
2381
|
-
};
|
|
2382
|
-
|
|
2383
|
-
/**
|
|
2384
|
-
* 清除所有暂停状态
|
|
2385
|
-
* @returns {boolean} 是否成功清除
|
|
2386
|
-
*/
|
|
2387
|
-
Eventer.prototype.clearPaused = function () {
|
|
2388
|
-
if (!this.config.pause_enabled) {
|
|
2389
|
-
this.log('warn', '暂停功能未启用');
|
|
2390
|
-
return false;
|
|
2391
|
-
}
|
|
2392
|
-
|
|
2393
|
-
let cleared = false;
|
|
2394
|
-
|
|
2395
|
-
if (this._paused_global) {
|
|
2396
|
-
this._paused_global = false;
|
|
2397
|
-
cleared = true;
|
|
2398
|
-
}
|
|
2399
|
-
|
|
2400
|
-
if (this._paused.size > 0) {
|
|
2401
|
-
this._paused.clear();
|
|
2402
|
-
cleared = true;
|
|
2403
|
-
}
|
|
2404
|
-
|
|
2405
|
-
if (this._paused_space.size > 0) {
|
|
2406
|
-
this._paused_space.clear();
|
|
2407
|
-
cleared = true;
|
|
2408
|
-
}
|
|
2409
|
-
|
|
2410
|
-
if (cleared) {
|
|
2411
|
-
this.log('info', '所有暂停状态已清除');
|
|
2412
|
-
}
|
|
2413
|
-
|
|
2414
|
-
return cleared;
|
|
2415
|
-
};
|
|
2416
|
-
|
|
2417
|
-
let eventer = new Eventer();
|
|
2418
|
-
|
|
2419
|
-
module.exports = {
|
|
2420
|
-
Eventer,
|
|
2421
|
-
eventer
|
|
2422
|
-
};
|
|
1
|
+
/* eslint-disable mm_eslint/function-name */
|
|
2
|
+
require('./global.js');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 事件类 - 增强版EventBus实现
|
|
6
|
+
*/
|
|
7
|
+
class Eventer {
|
|
8
|
+
static config = {
|
|
9
|
+
max_list: 10, // 最大监听器数量
|
|
10
|
+
default_name: 'default', // 默认命名空间
|
|
11
|
+
chain_enabled: true, // 是否启用链式触发
|
|
12
|
+
auto_clean: true, // 是否自动清理空的事件列表
|
|
13
|
+
error: null, // 全局错误处理函数
|
|
14
|
+
pause_enabled: true, // 是否启用暂停功能
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
// 日志对象
|
|
18
|
+
#logger = $.log || console;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* 构造函数
|
|
22
|
+
* @param {object} config 配置参数
|
|
23
|
+
*/
|
|
24
|
+
constructor(config) {
|
|
25
|
+
this.config = {
|
|
26
|
+
...Eventer.config,
|
|
27
|
+
...config || {}
|
|
28
|
+
};
|
|
29
|
+
// 是否为插件
|
|
30
|
+
this.is_plugin = false;
|
|
31
|
+
// 事件字典 - 支持命名空间
|
|
32
|
+
this._dict = {};
|
|
33
|
+
// 事件中间件
|
|
34
|
+
this._middleware = [];
|
|
35
|
+
// 命名空间映射
|
|
36
|
+
this._space = {};
|
|
37
|
+
// 事件链映射 { 'event1': ['event2', 'event3'], 'space:event1': ['event4'] }
|
|
38
|
+
this._chain = {};
|
|
39
|
+
// 进行中的任务映射,用于取消操作
|
|
40
|
+
this._tasks = new Map();
|
|
41
|
+
// 暂停状态管理
|
|
42
|
+
this._paused = new Set(); // 暂停的单个事件
|
|
43
|
+
this._paused_space = new Set(); // 暂停的命名空间
|
|
44
|
+
this._paused_global = false; // 全局暂停状态
|
|
45
|
+
// 初始化默认命名空间
|
|
46
|
+
this._space[this.config.default_name] = true;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* 设置日志记录器
|
|
51
|
+
* @param {object} logger 日志记录器对象
|
|
52
|
+
*/
|
|
53
|
+
setLogger(logger) {
|
|
54
|
+
this.#logger = logger;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* 获取日志记录器
|
|
59
|
+
* @returns {object} 日志记录器对象
|
|
60
|
+
*/
|
|
61
|
+
getLogger() {
|
|
62
|
+
return this.#logger;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* 日志输出
|
|
67
|
+
* @param {string} level 日志级别
|
|
68
|
+
* @param {string} message 日志消息
|
|
69
|
+
* @param {...any} params 日志参数
|
|
70
|
+
*/
|
|
71
|
+
log(level, message, ...params) {
|
|
72
|
+
this.getLogger()[level](`[${this.constructor.name}] ${message}`, ...params);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* 初始化事件管理器
|
|
78
|
+
* @param {...any} args 初始化参数
|
|
79
|
+
* @returns {Eventer} 返回事件管理器实例
|
|
80
|
+
* @private
|
|
81
|
+
*/
|
|
82
|
+
Eventer.prototype._init = async function (...args) {
|
|
83
|
+
// 初始化逻辑
|
|
84
|
+
return this;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* 初始化事件管理器
|
|
89
|
+
* @param {...any} args 初始化参数
|
|
90
|
+
* @returns {Eventer} 返回事件管理器实例
|
|
91
|
+
*/
|
|
92
|
+
Eventer.prototype.init = async function (...args) {
|
|
93
|
+
return this._init(...args);
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* 监听事件(支持命名空间和优先级)
|
|
98
|
+
* @param {string} key 事件关键字,支持space:key格式
|
|
99
|
+
* @param {object} func 触发函数
|
|
100
|
+
* @throws {Error} 事件关键字必须是非空字符串
|
|
101
|
+
* @throws {Error} 事件处理函数必须是一个函数
|
|
102
|
+
*/
|
|
103
|
+
Eventer.prototype._validateOnParams = function (key, func) {
|
|
104
|
+
if (!key || typeof key !== 'string') {
|
|
105
|
+
throw new Error('事件关键字必须是非空字符串');
|
|
106
|
+
}
|
|
107
|
+
if (typeof func !== 'function') {
|
|
108
|
+
throw new Error('事件处理函数必须是一个函数');
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
Eventer.prototype._parseEventKey = function (key, ns) {
|
|
113
|
+
let parsed = this._parseKey(key);
|
|
114
|
+
let space = ns || parsed.space;
|
|
115
|
+
let event_key = parsed.key;
|
|
116
|
+
let full_key = `${space}:${event_key}`;
|
|
117
|
+
return { space, event_key, full_key };
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
Eventer.prototype._initNamespace = function (space, event_key) {
|
|
121
|
+
if (!this._dict[space]) {
|
|
122
|
+
this._dict[space] = {};
|
|
123
|
+
this._space[space] = true;
|
|
124
|
+
}
|
|
125
|
+
if (!this._dict[space][event_key]) {
|
|
126
|
+
this._dict[space][event_key] = [];
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
Eventer.prototype._generateDefaultName = function (func) {
|
|
131
|
+
return func.name || `handler_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
Eventer.prototype._wrapFunction = function (func, params) {
|
|
135
|
+
let wrapped_func = func;
|
|
136
|
+
|
|
137
|
+
if (params.throttle) {
|
|
138
|
+
wrapped_func = this._throttle(func, params.throttle);
|
|
139
|
+
} else if (params.debounce) {
|
|
140
|
+
wrapped_func = this._debounce(func, params.debounce);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (params.timeout && typeof params.timeout === 'number' && params.timeout > 0) {
|
|
144
|
+
let original_func = wrapped_func;
|
|
145
|
+
wrapped_func = async function (...args) {
|
|
146
|
+
const timeoutPromise = new Promise((resolve, reject) => {
|
|
147
|
+
setTimeout(() => reject(new Error(`事件执行超时 (${params.timeout}ms)`)), params.timeout);
|
|
148
|
+
});
|
|
149
|
+
return Promise.race([original_func.apply(this, args), timeoutPromise]);
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return wrapped_func;
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
Eventer.prototype._createHandlerObj = function (config) {
|
|
157
|
+
var handler = {
|
|
158
|
+
name: config.name,
|
|
159
|
+
func: config.wrapped_func,
|
|
160
|
+
original_func: config.func,
|
|
161
|
+
times: config.times,
|
|
162
|
+
priority: config.priority,
|
|
163
|
+
created_at: Date.now(),
|
|
164
|
+
last_executed: null
|
|
165
|
+
};
|
|
166
|
+
return handler;
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
Eventer.prototype._findHandlerIndex = function (list, name) {
|
|
170
|
+
for (let i = 0; i < list.length; i++) {
|
|
171
|
+
if (list[i].name === name) {
|
|
172
|
+
return i;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return -1;
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
Eventer.prototype._checkListenerLimit = function (space, event_key, list) {
|
|
179
|
+
let max_list = this.config.max_list;
|
|
180
|
+
if (max_list > 0 && list.length >= max_list) {
|
|
181
|
+
this.log('warn', `警告: '${space}:${event_key}' 事件的监听器数量已达到 ${max_list},可能导致内存泄漏。使用 set_max_listeners() 方法可以增加限制。`);
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
Eventer.prototype._createHandlerResult = function (space, index, name, full_key) {
|
|
186
|
+
return {
|
|
187
|
+
space,
|
|
188
|
+
index,
|
|
189
|
+
name,
|
|
190
|
+
remove: () => this.off(full_key, name)
|
|
191
|
+
};
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* 监听事件(支持命名空间和优先级)
|
|
196
|
+
* @param {string} key 事件关键字,支持space:key格式
|
|
197
|
+
* @param {object} func 触发函数
|
|
198
|
+
* @param {string} name 增加名称,方便删除,当出现相同名称时会被覆盖
|
|
199
|
+
* @param {object} options 其他选项,如throttle、debounce、timeout等
|
|
200
|
+
* @returns {object} 返回事件信息对象 {space, index, name, remove},remove为移除该事件的函数
|
|
201
|
+
*/
|
|
202
|
+
Eventer.prototype.on = function (key, func, name, options) {
|
|
203
|
+
// 处理参数
|
|
204
|
+
let params = this._processOnParams(key, func, name, options);
|
|
205
|
+
|
|
206
|
+
// 验证参数
|
|
207
|
+
this._validateOnParams(params.key, params.func);
|
|
208
|
+
|
|
209
|
+
// 处理事件添加
|
|
210
|
+
return this._addEventHandler(params);
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
Eventer.prototype._processOnParams = function (key, func, name, options) {
|
|
214
|
+
// 支持两种调用方式:便捷方式和配置对象方式
|
|
215
|
+
if (typeof key === 'object' && key !== null) {
|
|
216
|
+
// 配置对象方式
|
|
217
|
+
return this._extractOnParams(key);
|
|
218
|
+
} else {
|
|
219
|
+
// 便捷方式
|
|
220
|
+
let opts = options || {};
|
|
221
|
+
return {
|
|
222
|
+
key: key,
|
|
223
|
+
func: func,
|
|
224
|
+
name: name,
|
|
225
|
+
times: opts.times || -1,
|
|
226
|
+
priority: opts.priority || 0,
|
|
227
|
+
ns: opts.ns || null
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
Eventer.prototype._addEventHandler = function (params) {
|
|
233
|
+
const { key: event_key, func: event_func, name: event_name,
|
|
234
|
+
times: event_times, priority: event_priority, ns } = params;
|
|
235
|
+
|
|
236
|
+
// 解析命名空间
|
|
237
|
+
const { space, event_key: parsed_event_key, full_key } = this._parseEventKey(event_key, ns);
|
|
238
|
+
|
|
239
|
+
// 初始化命名空间和事件数组
|
|
240
|
+
this._initNamespace(space, parsed_event_key);
|
|
241
|
+
|
|
242
|
+
// 设置默认名称
|
|
243
|
+
let final_name = event_name || this._generateDefaultName(event_func);
|
|
244
|
+
|
|
245
|
+
// 应用节流或防抖
|
|
246
|
+
let wrapped_func = this._wrapFunction(event_func, params);
|
|
247
|
+
|
|
248
|
+
// 创建事件对象
|
|
249
|
+
let obj = this._createHandlerObj({
|
|
250
|
+
name: final_name,
|
|
251
|
+
wrapped_func: wrapped_func,
|
|
252
|
+
func: event_func,
|
|
253
|
+
times: event_times,
|
|
254
|
+
priority: event_priority
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
// 处理事件添加逻辑
|
|
258
|
+
return this._handleEventAddition({ space, event_key: parsed_event_key, full_key, final_name, obj });
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
Eventer.prototype._extractOnParams = function (config) {
|
|
262
|
+
return {
|
|
263
|
+
key: config.key,
|
|
264
|
+
func: config.func,
|
|
265
|
+
name: config.name,
|
|
266
|
+
times: config.times || -1,
|
|
267
|
+
priority: config.priority || 0,
|
|
268
|
+
ns: config.ns || null
|
|
269
|
+
};
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
Eventer.prototype._processOnceParams = function (key, func, name, options) {
|
|
273
|
+
// 支持两种调用方式:便捷方式和配置对象方式
|
|
274
|
+
if (typeof key === 'object' && key !== null) {
|
|
275
|
+
// 配置对象方式
|
|
276
|
+
let params = this._extractOnParams(key);
|
|
277
|
+
params.times = 1; // 强制设置为仅执行一次
|
|
278
|
+
return params;
|
|
279
|
+
} else {
|
|
280
|
+
// 便捷方式
|
|
281
|
+
let opts = options || {};
|
|
282
|
+
return {
|
|
283
|
+
key: key,
|
|
284
|
+
func: func,
|
|
285
|
+
name: name,
|
|
286
|
+
times: 1, // 强制设置为仅执行一次
|
|
287
|
+
priority: opts.priority || 0,
|
|
288
|
+
ns: opts.ns || null
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
Eventer.prototype._handleEventAddition = function (config) {
|
|
294
|
+
const { space, event_key, full_key, final_name, obj } = config;
|
|
295
|
+
let list = this._dict[space][event_key];
|
|
296
|
+
let idx = this._findHandlerIndex(list, final_name);
|
|
297
|
+
|
|
298
|
+
if (idx >= 0) {
|
|
299
|
+
// 覆盖已存在的同名监听器
|
|
300
|
+
Object.assign(list[idx], obj);
|
|
301
|
+
// 重新排序
|
|
302
|
+
this._sort(list);
|
|
303
|
+
return this._createHandlerResult(space, idx, final_name, full_key);
|
|
304
|
+
} else {
|
|
305
|
+
// 检查监听器数量是否超过限制
|
|
306
|
+
this._checkListenerLimit(space, event_key, list);
|
|
307
|
+
|
|
308
|
+
// 添加新事件
|
|
309
|
+
list.push(obj);
|
|
310
|
+
// 按优先级排序
|
|
311
|
+
this._sort(list);
|
|
312
|
+
return this._createHandlerResult(space, list.length - 1, final_name, full_key);
|
|
313
|
+
}
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* 监听事件(仅执行一次)
|
|
318
|
+
* @param {string | object} key 事件关键,支持space:key格式,或配置对象
|
|
319
|
+
* @param {object} func 触发函数
|
|
320
|
+
* @param {string} name 增加名称,方便删除,当出现相同名称时会被覆盖
|
|
321
|
+
* @param {object} options 其他选项
|
|
322
|
+
* @returns {object} 返回事件信息对象 {space, idx, name}
|
|
323
|
+
*/
|
|
324
|
+
Eventer.prototype.once = function (key, func, name, options) {
|
|
325
|
+
// 处理参数
|
|
326
|
+
let params = this._processOnceParams(key, func, name, options);
|
|
327
|
+
|
|
328
|
+
// 验证参数
|
|
329
|
+
this._validateOnParams(params.key, params.func);
|
|
330
|
+
|
|
331
|
+
// 处理事件添加
|
|
332
|
+
return this._addEventHandler(params);
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* 统一的事件执行引擎
|
|
337
|
+
* @param {string} key 事件关键字,支持space:key格式
|
|
338
|
+
* @throws {Error} 事件关键字必须是非空字符串
|
|
339
|
+
* @private
|
|
340
|
+
*/
|
|
341
|
+
Eventer.prototype._validateExec = function (key) {
|
|
342
|
+
if (!key || typeof key !== 'string') {
|
|
343
|
+
throw new Error('事件关键字必须是非空字符串');
|
|
344
|
+
}
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
Eventer.prototype._createCtx = function (key, params) {
|
|
348
|
+
let parsed = this._parseKey(key);
|
|
349
|
+
let space = parsed.space;
|
|
350
|
+
let event_key = parsed.key;
|
|
351
|
+
let full_key = `${space}:${event_key}`;
|
|
352
|
+
let start_time = Date.now();
|
|
353
|
+
|
|
354
|
+
const ctx = {
|
|
355
|
+
space,
|
|
356
|
+
event: event_key,
|
|
357
|
+
full_event: full_key,
|
|
358
|
+
params,
|
|
359
|
+
results: [],
|
|
360
|
+
start_time: start_time,
|
|
361
|
+
executed: 0,
|
|
362
|
+
error_count: 0,
|
|
363
|
+
cancelled: false,
|
|
364
|
+
cancel: () => {
|
|
365
|
+
ctx.cancelled = true;
|
|
366
|
+
this._cancelTasks(full_key);
|
|
367
|
+
}
|
|
368
|
+
};
|
|
369
|
+
|
|
370
|
+
return { ctx, space, event_key, full_key, start_time };
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
Eventer.prototype._cancelTasks = function (full_key) {
|
|
374
|
+
try {
|
|
375
|
+
if (this._tasks.has(full_key)) {
|
|
376
|
+
let tasks = this._tasks.get(full_key);
|
|
377
|
+
tasks.forEach(task => {
|
|
378
|
+
if (task && typeof task.cancel === 'function') {
|
|
379
|
+
try {
|
|
380
|
+
task.cancel();
|
|
381
|
+
} catch (cancel_error) {
|
|
382
|
+
this.log('error', `任务取消失败 [${full_key}] - ${task.id}`, cancel_error);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
this._tasks.delete(full_key);
|
|
387
|
+
}
|
|
388
|
+
} catch (cancel_global_error) {
|
|
389
|
+
this.log('error', `任务取消过程异常 [${full_key}]`, cancel_global_error);
|
|
390
|
+
}
|
|
391
|
+
};
|
|
392
|
+
|
|
393
|
+
Eventer.prototype._initTaskList = function (full_key) {
|
|
394
|
+
try {
|
|
395
|
+
this._tasks.set(full_key, []);
|
|
396
|
+
} catch (task_init_error) {
|
|
397
|
+
this.log('error', `任务列表初始化失败 [${full_key}]`, task_init_error);
|
|
398
|
+
}
|
|
399
|
+
};
|
|
400
|
+
|
|
401
|
+
Eventer.prototype._runBeforeMiddleware = async function (ctx, full_key) {
|
|
402
|
+
try {
|
|
403
|
+
await this._runMiddleware('before', ctx);
|
|
404
|
+
if (ctx.cancelled) {
|
|
405
|
+
this._cleanupTasks(full_key);
|
|
406
|
+
return true;
|
|
407
|
+
}
|
|
408
|
+
return false;
|
|
409
|
+
} catch (error) {
|
|
410
|
+
this.log('error', `事件中间件执行失败 [${ctx.space}:${ctx.event}]`, error);
|
|
411
|
+
if (this.config.error_handler && typeof this.config.error_handler === 'function') {
|
|
412
|
+
this.config.error_handler(error, { type: 'middleware', stage: 'before', ctx });
|
|
413
|
+
}
|
|
414
|
+
return false;
|
|
415
|
+
}
|
|
416
|
+
};
|
|
417
|
+
|
|
418
|
+
Eventer.prototype._cleanupTasks = function (full_key) {
|
|
419
|
+
try {
|
|
420
|
+
this._tasks.delete(full_key);
|
|
421
|
+
} catch (cleanup_error) {
|
|
422
|
+
this.log('error', `任务清理失败 [${full_key}]`, cleanup_error);
|
|
423
|
+
}
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
Eventer.prototype._executeStrategy = async function (config) {
|
|
427
|
+
const { list, params, ctx, full_key, arr, options } = config;
|
|
428
|
+
|
|
429
|
+
try {
|
|
430
|
+
if (options.exec_mode === 'parallel') {
|
|
431
|
+
await this._executeParallel({ list, params, ctx, full_key, arr });
|
|
432
|
+
} else if (options.exec_mode === 'race') {
|
|
433
|
+
ctx.race_result = await this._executeRace({ list, params, ctx, full_key, arr });
|
|
434
|
+
} else if (options.exec_mode === 'waterfall') {
|
|
435
|
+
await this._executeWaterfall({
|
|
436
|
+
list, params, ctx, full_key, arr,
|
|
437
|
+
initial_value: options.initial_value
|
|
438
|
+
});
|
|
439
|
+
} else {
|
|
440
|
+
await this._executeSequential({ list, params, ctx, full_key, arr });
|
|
441
|
+
}
|
|
442
|
+
} catch (exec_error) {
|
|
443
|
+
this.log('error', `事件执行策略异常 [${full_key}]`, exec_error);
|
|
444
|
+
if (this.config.error_handler && typeof this.config.error_handler === 'function') {
|
|
445
|
+
this.config.error_handler(exec_error, { type: 'execution', ctx });
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
};
|
|
449
|
+
|
|
450
|
+
Eventer.prototype._removeEvents = function (space, key, arr) {
|
|
451
|
+
try {
|
|
452
|
+
for (let i = 0; i < arr.length; i++) {
|
|
453
|
+
this.del(`${space}:${key}`, arr[i]);
|
|
454
|
+
}
|
|
455
|
+
} catch (remove_error) {
|
|
456
|
+
this.log('error', `事件移除失败 [${space}:${key}]`, remove_error);
|
|
457
|
+
}
|
|
458
|
+
};
|
|
459
|
+
|
|
460
|
+
Eventer.prototype._autoCleanup = function (space, key) {
|
|
461
|
+
try {
|
|
462
|
+
if (this.config.auto_clean && this._dict[space] && this._dict[space][key] &&
|
|
463
|
+
this._dict[space][key].length === 0) {
|
|
464
|
+
delete this._dict[space][key];
|
|
465
|
+
if (this._dict[space] && Object.keys(this._dict[space]).length === 0) {
|
|
466
|
+
delete this._dict[space];
|
|
467
|
+
delete this._space[space];
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
} catch (cleanup_error) {
|
|
471
|
+
this.log('error', `自动清理失败 [${space}:${key}]`, cleanup_error);
|
|
472
|
+
}
|
|
473
|
+
};
|
|
474
|
+
|
|
475
|
+
Eventer.prototype._runAfterMiddleware = async function (ctx, start_time) {
|
|
476
|
+
try {
|
|
477
|
+
ctx.end_time = Date.now();
|
|
478
|
+
ctx.duration = ctx.end_time - start_time;
|
|
479
|
+
await this._runMiddleware('after', ctx);
|
|
480
|
+
} catch (error) {
|
|
481
|
+
this.log('error', `事件后置中间件执行失败 [${ctx.space}:${ctx.event}]`, error);
|
|
482
|
+
if (this.config.error_handler && typeof this.config.error_handler === 'function') {
|
|
483
|
+
this.config.error_handler(error, { type: 'middleware', stage: 'after', ctx });
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
};
|
|
487
|
+
|
|
488
|
+
Eventer.prototype._executeEventChain = async function (ctx, full_key, params) {
|
|
489
|
+
if (!ctx.cancelled && this.config.chain_enabled && this._chain[full_key]) {
|
|
490
|
+
try {
|
|
491
|
+
await this._triggerChain(full_key, params);
|
|
492
|
+
} catch (chain_error) {
|
|
493
|
+
this.log('error', `事件链执行失败 [${full_key}]`, chain_error);
|
|
494
|
+
if (this.config.error_handler && typeof this.config.error_handler === 'function') {
|
|
495
|
+
this.config.error_handler(chain_error, { type: 'chain', ctx });
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
};
|
|
500
|
+
|
|
501
|
+
Eventer.prototype._buildSafeResult = function (ctx) {
|
|
502
|
+
try {
|
|
503
|
+
return {
|
|
504
|
+
results: ctx.results || [],
|
|
505
|
+
cancelled: ctx.cancelled || false,
|
|
506
|
+
cancel: ctx.cancel || (() => { }),
|
|
507
|
+
race: ctx.race_result,
|
|
508
|
+
waterfall: ctx.results && ctx.results.length > 0 ? ctx.results[ctx.results.length - 1]
|
|
509
|
+
: undefined
|
|
510
|
+
};
|
|
511
|
+
} catch (return_error) {
|
|
512
|
+
this.log('error', `结果构造失败 [${ctx.full_event}]`, return_error);
|
|
513
|
+
return {
|
|
514
|
+
results: [],
|
|
515
|
+
cancelled: true,
|
|
516
|
+
cancel: () => { },
|
|
517
|
+
error: return_error
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
};
|
|
521
|
+
|
|
522
|
+
Eventer.prototype._execute = async function (key, options = {}, ...params) {
|
|
523
|
+
this._validateExec(key);
|
|
524
|
+
|
|
525
|
+
const { ctx, space, event_key, full_key, start_time } = this._createCtx(key, params);
|
|
526
|
+
|
|
527
|
+
if (this.isPaused(full_key)) {
|
|
528
|
+
return this._createPausedResult();
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
let list = this._dict[space] && this._dict[space][event_key];
|
|
532
|
+
const arr = [];
|
|
533
|
+
|
|
534
|
+
if (list && list.length > 0) {
|
|
535
|
+
await this._executeEventList({
|
|
536
|
+
list, params, ctx, full_key, arr, options, space, event_key, start_time
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
await this._executeEventChain(ctx, full_key, params);
|
|
541
|
+
return this._buildSafeResult(ctx);
|
|
542
|
+
};
|
|
543
|
+
|
|
544
|
+
/**
|
|
545
|
+
* 创建暂停状态的结果对象
|
|
546
|
+
* @returns {object} 暂停状态的结果
|
|
547
|
+
* @private
|
|
548
|
+
*/
|
|
549
|
+
Eventer.prototype._createPausedResult = function () {
|
|
550
|
+
return {
|
|
551
|
+
results: [],
|
|
552
|
+
cancelled: false,
|
|
553
|
+
paused: true,
|
|
554
|
+
/**
|
|
555
|
+
* 取消函数
|
|
556
|
+
*/
|
|
557
|
+
cancel: () => { }
|
|
558
|
+
};
|
|
559
|
+
};
|
|
560
|
+
|
|
561
|
+
/**
|
|
562
|
+
* 执行事件列表
|
|
563
|
+
* @param {object} config 配置参数
|
|
564
|
+
* @param {Array} config.list 事件列表
|
|
565
|
+
* @param {Array} config.params 参数
|
|
566
|
+
* @param {object} config.ctx 上下文
|
|
567
|
+
* @param {string} config.full_key 完整键名
|
|
568
|
+
* @param {Array} config.arr 数组
|
|
569
|
+
* @param {object} config.options 选项
|
|
570
|
+
* @param {string} config.space 命名空间
|
|
571
|
+
* @param {string} config.event_key 事件键
|
|
572
|
+
* @param {number} config.start_time 开始时间
|
|
573
|
+
* @param {string} config.strategy 执行策略,默认sequential
|
|
574
|
+
* @returns {object} 返回执行结果
|
|
575
|
+
* @private
|
|
576
|
+
*/
|
|
577
|
+
Eventer.prototype._executeEventList = async function (config) {
|
|
578
|
+
const { list, params, ctx, full_key, arr, options, space, event_key, start_time } = config;
|
|
579
|
+
|
|
580
|
+
this._initTaskList(full_key);
|
|
581
|
+
|
|
582
|
+
let cancelled = await this._runBeforeMiddleware(ctx, full_key);
|
|
583
|
+
if (cancelled) {
|
|
584
|
+
return {
|
|
585
|
+
results: [],
|
|
586
|
+
cancelled: true,
|
|
587
|
+
cancel: ctx.cancel
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
await this._executeStrategy({ list, params, ctx, full_key, arr, options });
|
|
592
|
+
|
|
593
|
+
this._cleanupTasks(full_key);
|
|
594
|
+
this._removeEvents(space, event_key, arr);
|
|
595
|
+
this._autoCleanup(space, event_key);
|
|
596
|
+
await this._runAfterMiddleware(ctx, start_time);
|
|
597
|
+
};
|
|
598
|
+
|
|
599
|
+
/**
|
|
600
|
+
* 顺序执行事件处理函数
|
|
601
|
+
* @param {object} config 配置参数
|
|
602
|
+
* @private
|
|
603
|
+
*/
|
|
604
|
+
Eventer.prototype._executeSequential = async function (config) {
|
|
605
|
+
const { list, params, ctx, full_key, arr } = config;
|
|
606
|
+
|
|
607
|
+
for (let i = 0; i < list.length && !ctx.cancelled; i++) {
|
|
608
|
+
let o = list[i];
|
|
609
|
+
ctx.executed++;
|
|
610
|
+
o.last_executed = Date.now();
|
|
611
|
+
|
|
612
|
+
// 创建并执行单个任务
|
|
613
|
+
await this._execSingleTask(o, params, ctx, { full_key, arr });
|
|
614
|
+
}
|
|
615
|
+
};
|
|
616
|
+
|
|
617
|
+
Eventer.prototype._execSingleTask = async function (o, params, ctx, options) {
|
|
618
|
+
const { full_key, arr } = options;
|
|
619
|
+
|
|
620
|
+
// 创建任务
|
|
621
|
+
let task = this._createTask(o, full_key);
|
|
622
|
+
|
|
623
|
+
try {
|
|
624
|
+
// 执行事件处理函数
|
|
625
|
+
let result = await o.func.apply(o, params);
|
|
626
|
+
|
|
627
|
+
// 处理成功结果
|
|
628
|
+
this._handleSuccessResult({ result, o, ctx, arr, task });
|
|
629
|
+
} catch (e) {
|
|
630
|
+
// 处理错误
|
|
631
|
+
this._handleSeqTaskError(e, o, ctx, task);
|
|
632
|
+
}
|
|
633
|
+
};
|
|
634
|
+
|
|
635
|
+
Eventer.prototype._createTask = function (o, full_key) {
|
|
636
|
+
let task_id = `${o.name}_${Date.now()}`;
|
|
637
|
+
let cancelled = false;
|
|
638
|
+
const task = {
|
|
639
|
+
id: task_id,
|
|
640
|
+
cancel: () => { cancelled = true; }
|
|
641
|
+
};
|
|
642
|
+
|
|
643
|
+
// 添加到进行中的任务列表(防御性处理重入调用导致 key 已被清理的情况)
|
|
644
|
+
let tasks = this._tasks.get(full_key);
|
|
645
|
+
if (!tasks) {
|
|
646
|
+
tasks = [];
|
|
647
|
+
this._tasks.set(full_key, tasks);
|
|
648
|
+
}
|
|
649
|
+
tasks.push(task);
|
|
650
|
+
|
|
651
|
+
return { task, tasks, cancelled };
|
|
652
|
+
};
|
|
653
|
+
|
|
654
|
+
Eventer.prototype._handleSuccessResult = function (config) {
|
|
655
|
+
const { result, o, ctx, arr, task } = config;
|
|
656
|
+
|
|
657
|
+
// 如果任务已取消,则不添加结果
|
|
658
|
+
if (!task.cancelled && !ctx.cancelled) {
|
|
659
|
+
ctx.results.push(result);
|
|
660
|
+
|
|
661
|
+
// 处理执行次数限制
|
|
662
|
+
if (o.times >= 0) {
|
|
663
|
+
o.times--;
|
|
664
|
+
if (o.times <= 0) {
|
|
665
|
+
arr.push(o.name);
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
// 从进行中的任务列表中移除
|
|
671
|
+
task.tasks.splice(task.tasks.indexOf(task.task), 1);
|
|
672
|
+
};
|
|
673
|
+
|
|
674
|
+
Eventer.prototype._handleSeqTaskError = function (e, o, ctx, task) {
|
|
675
|
+
ctx.error_count++;
|
|
676
|
+
this.log('error', `事件执行失败 [${ctx.space}:${ctx.event}] - ${o.name}`, e);
|
|
677
|
+
|
|
678
|
+
const error_result = {
|
|
679
|
+
_error: true,
|
|
680
|
+
error: e,
|
|
681
|
+
handler: o.name,
|
|
682
|
+
timestamp: Date.now()
|
|
683
|
+
};
|
|
684
|
+
|
|
685
|
+
ctx.results.push(error_result);
|
|
686
|
+
|
|
687
|
+
// 全局错误处理器
|
|
688
|
+
if (this.config.error_handler && typeof this.config.error_handler === 'function') {
|
|
689
|
+
this.config.error_handler(e, { type: 'handler', handler: o.name, ctx });
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
// 从进行中的任务列表中移除
|
|
693
|
+
task.tasks.splice(task.tasks.indexOf(task.task), 1);
|
|
694
|
+
};
|
|
695
|
+
|
|
696
|
+
/**
|
|
697
|
+
* 并行执行事件处理函数
|
|
698
|
+
* @param {object} config 配置参数
|
|
699
|
+
* @private
|
|
700
|
+
*/
|
|
701
|
+
Eventer.prototype._executeParallel = async function (config) {
|
|
702
|
+
const { list, params, ctx, full_key, arr } = config;
|
|
703
|
+
let concurrency = this._getConcurrency(params);
|
|
704
|
+
// eslint-disable-next-line mm_eslint/class-instance-name
|
|
705
|
+
const proc_results = new Array(list.length);
|
|
706
|
+
|
|
707
|
+
if (concurrency < Infinity) {
|
|
708
|
+
await this._executeBatches({
|
|
709
|
+
list, params, ctx, full_key, arr, concurrency, proc_results
|
|
710
|
+
});
|
|
711
|
+
} else {
|
|
712
|
+
await this._executeAllParallel({ list, params, ctx, full_key, arr, proc_results });
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
this._setResults(ctx, proc_results);
|
|
716
|
+
};
|
|
717
|
+
|
|
718
|
+
Eventer.prototype._getConcurrency = function (params) {
|
|
719
|
+
return params.options && typeof params.options.concurrency === 'number' ?
|
|
720
|
+
params.options.concurrency : Infinity;
|
|
721
|
+
};
|
|
722
|
+
|
|
723
|
+
Eventer.prototype._executeBatches = async function (config) {
|
|
724
|
+
const { list, params, ctx, full_key, arr, concurrency, proc_results } = config;
|
|
725
|
+
|
|
726
|
+
for (let i = 0; i < list.length && !ctx.cancelled; i += concurrency) {
|
|
727
|
+
let batch = list.slice(i, i + concurrency);
|
|
728
|
+
let batch_promises = batch.map((obj, batch_idx) => {
|
|
729
|
+
let global = i + batch_idx;
|
|
730
|
+
return this._executeSingleTask({
|
|
731
|
+
obj, params, ctx, full_key, arr, idx: global, proc_results
|
|
732
|
+
});
|
|
733
|
+
});
|
|
734
|
+
|
|
735
|
+
await Promise.allSettled(batch_promises);
|
|
736
|
+
}
|
|
737
|
+
};
|
|
738
|
+
|
|
739
|
+
Eventer.prototype._executeAllParallel = async function (config) {
|
|
740
|
+
const { list, params, ctx, full_key, arr, proc_results } = config;
|
|
741
|
+
|
|
742
|
+
let promises = list.map((obj, idx) => {
|
|
743
|
+
return this._executeSingleTask({ obj, params, ctx, full_key, arr, idx, proc_results });
|
|
744
|
+
});
|
|
745
|
+
|
|
746
|
+
await Promise.allSettled(promises);
|
|
747
|
+
};
|
|
748
|
+
|
|
749
|
+
Eventer.prototype._setResults = function (ctx, proc_results) {
|
|
750
|
+
ctx.results = proc_results.filter(result => result !== undefined);
|
|
751
|
+
};
|
|
752
|
+
|
|
753
|
+
/**
|
|
754
|
+
* 瀑布流执行事件处理函数
|
|
755
|
+
* @param {object} config 配置参数
|
|
756
|
+
* @private
|
|
757
|
+
*/
|
|
758
|
+
Eventer.prototype._executeWaterfall = async function (config) {
|
|
759
|
+
const { list, params, ctx, full_key, arr, initial_value } = config;
|
|
760
|
+
let wate_value = this._getInitialValue(params, initial_value);
|
|
761
|
+
|
|
762
|
+
for (let i = 0; i < list.length && !ctx.cancelled; i++) {
|
|
763
|
+
let obj = list[i];
|
|
764
|
+
ctx.executed++;
|
|
765
|
+
obj.last_executed = Date.now();
|
|
766
|
+
|
|
767
|
+
let task = this._createWaterfallTask(obj, full_key);
|
|
768
|
+
wate_value = await this._execWaterfallStep({
|
|
769
|
+
obj, params, ctx, arr, task, wate_value
|
|
770
|
+
});
|
|
771
|
+
}
|
|
772
|
+
};
|
|
773
|
+
|
|
774
|
+
Eventer.prototype._getInitialValue = function (params, initial_value) {
|
|
775
|
+
return initial_value !== undefined ? initial_value : (params.length > 0 ? params[0] : undefined);
|
|
776
|
+
};
|
|
777
|
+
|
|
778
|
+
Eventer.prototype._createWaterfallTask = function (obj, full_key) {
|
|
779
|
+
let task_id = `${obj.name}_${Date.now()}`;
|
|
780
|
+
let cancelled = false;
|
|
781
|
+
const task = {
|
|
782
|
+
id: task_id,
|
|
783
|
+
cancel: () => { cancelled = true; }
|
|
784
|
+
};
|
|
785
|
+
|
|
786
|
+
let tasks = this._tasks.get(full_key);
|
|
787
|
+
if (!tasks) {
|
|
788
|
+
tasks = [];
|
|
789
|
+
this._tasks.set(full_key, tasks);
|
|
790
|
+
}
|
|
791
|
+
tasks.push(task);
|
|
792
|
+
|
|
793
|
+
return { task, tasks, cancelled };
|
|
794
|
+
};
|
|
795
|
+
|
|
796
|
+
Eventer.prototype._execWaterfallStep = async function (config) {
|
|
797
|
+
const { obj, params, ctx, arr, task, wate_value } = config;
|
|
798
|
+
try {
|
|
799
|
+
let result = await obj.func.apply(obj, [wate_value, ...params.slice(1)]);
|
|
800
|
+
this._handleWfSuccess({ result, obj, ctx, arr, task });
|
|
801
|
+
return result;
|
|
802
|
+
} catch (e) {
|
|
803
|
+
this._handleWfError({ e, obj, ctx, task });
|
|
804
|
+
return wate_value;
|
|
805
|
+
}
|
|
806
|
+
};
|
|
807
|
+
|
|
808
|
+
Eventer.prototype._handleWfSuccess = function (config) {
|
|
809
|
+
const { result, obj, ctx, arr, task } = config;
|
|
810
|
+
if (!task.cancelled && !ctx.cancelled) {
|
|
811
|
+
ctx.results.push(result);
|
|
812
|
+
this._handleTimesLimit(obj, arr);
|
|
813
|
+
}
|
|
814
|
+
this._removeTask(task);
|
|
815
|
+
};
|
|
816
|
+
|
|
817
|
+
Eventer.prototype._handleWfError = function (config) {
|
|
818
|
+
const { e, obj, ctx, task } = config;
|
|
819
|
+
ctx.error_count++;
|
|
820
|
+
this.log('error', `事件执行失败 [${ctx.space}:${ctx.event}] - ${obj.name}`, e);
|
|
821
|
+
|
|
822
|
+
const error_result = {
|
|
823
|
+
_error: true,
|
|
824
|
+
error: e,
|
|
825
|
+
handler: obj.name,
|
|
826
|
+
timestamp: Date.now()
|
|
827
|
+
};
|
|
828
|
+
|
|
829
|
+
ctx.results.push(error_result);
|
|
830
|
+
this._callErrorHandler(e, obj, ctx);
|
|
831
|
+
this._removeTask(task);
|
|
832
|
+
};
|
|
833
|
+
|
|
834
|
+
Eventer.prototype._handleTimesLimit = function (obj, arr) {
|
|
835
|
+
if (obj.times >= 0) {
|
|
836
|
+
obj.times--;
|
|
837
|
+
if (obj.times <= 0) {
|
|
838
|
+
arr.push(obj.name);
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
};
|
|
842
|
+
|
|
843
|
+
Eventer.prototype._removeTask = function (task) {
|
|
844
|
+
task.tasks.splice(task.tasks.indexOf(task.task), 1);
|
|
845
|
+
};
|
|
846
|
+
|
|
847
|
+
Eventer.prototype._callErrorHandler = function (e, obj, ctx) {
|
|
848
|
+
if (this.config.error_handler && typeof this.config.error_handler === 'function') {
|
|
849
|
+
this.config.error_handler(e, { type: 'handler', handler: obj.name, ctx });
|
|
850
|
+
}
|
|
851
|
+
};
|
|
852
|
+
|
|
853
|
+
/**
|
|
854
|
+
* 竞争执行模式 - 返回第一个完成的结果
|
|
855
|
+
* @param {object} config 配置参数
|
|
856
|
+
* @param {Array} config.list 事件列表
|
|
857
|
+
* @param {Array} config.params 参数
|
|
858
|
+
* @param {object} config.ctx 上下文
|
|
859
|
+
* @param {string} config.strategy 执行策略
|
|
860
|
+
* @returns {Promise<object>} 返回包含results和cancel方法的对象
|
|
861
|
+
* @private
|
|
862
|
+
*/
|
|
863
|
+
Eventer.prototype._executeRace = async function (config) {
|
|
864
|
+
const { list, params, ctx, full_key, arr } = config;
|
|
865
|
+
let promises = this._createRacePromises({ list, params, ctx, full_key, arr });
|
|
866
|
+
|
|
867
|
+
return await this._runRace(promises);
|
|
868
|
+
};
|
|
869
|
+
|
|
870
|
+
Eventer.prototype._createRacePromises = function (config) {
|
|
871
|
+
const { list, params, ctx, full_key, arr } = config;
|
|
872
|
+
const promises = [];
|
|
873
|
+
|
|
874
|
+
for (let i = 0; i < list.length && !ctx.cancelled; i++) {
|
|
875
|
+
let obj = list[i];
|
|
876
|
+
ctx.executed++;
|
|
877
|
+
obj.last_executed = Date.now();
|
|
878
|
+
|
|
879
|
+
let promise = this._createRacePromise({ obj, params, ctx, full_key, arr });
|
|
880
|
+
promises.push(promise);
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
return promises;
|
|
884
|
+
};
|
|
885
|
+
|
|
886
|
+
Eventer.prototype._createRacePromise = function (config) {
|
|
887
|
+
const { obj, params, ctx, full_key, arr } = config;
|
|
888
|
+
let task = this._createRaceTask(obj, full_key);
|
|
889
|
+
|
|
890
|
+
return (async () => {
|
|
891
|
+
try {
|
|
892
|
+
let result = await obj.func.apply(obj, params);
|
|
893
|
+
return this._handleRaceSuccess({ result, obj, ctx, arr, task });
|
|
894
|
+
} catch (e) {
|
|
895
|
+
return this._handleRaceError(e, obj, ctx, task);
|
|
896
|
+
} finally {
|
|
897
|
+
this._removeTask(task);
|
|
898
|
+
}
|
|
899
|
+
})();
|
|
900
|
+
};
|
|
901
|
+
|
|
902
|
+
Eventer.prototype._createRaceTask = function (obj, full_key) {
|
|
903
|
+
let task_id = `${obj.name}_${Date.now()}`;
|
|
904
|
+
let cancelled = false;
|
|
905
|
+
const task = {
|
|
906
|
+
id: task_id,
|
|
907
|
+
cancel: () => { cancelled = true; }
|
|
908
|
+
};
|
|
909
|
+
|
|
910
|
+
let tasks = this._tasks.get(full_key);
|
|
911
|
+
if (!tasks) {
|
|
912
|
+
tasks = [];
|
|
913
|
+
this._tasks.set(full_key, tasks);
|
|
914
|
+
}
|
|
915
|
+
tasks.push(task);
|
|
916
|
+
|
|
917
|
+
return { task, tasks, cancelled };
|
|
918
|
+
};
|
|
919
|
+
|
|
920
|
+
Eventer.prototype._handleRaceSuccess = function (config) {
|
|
921
|
+
const { result, obj, ctx, arr, task } = config;
|
|
922
|
+
|
|
923
|
+
if (!task.cancelled && !ctx.cancelled) {
|
|
924
|
+
ctx.results.push(result);
|
|
925
|
+
this._handleTimesLimit(obj, arr);
|
|
926
|
+
return { success: true, result, handler: obj.name };
|
|
927
|
+
}
|
|
928
|
+
return { success: false, cancelled: true };
|
|
929
|
+
};
|
|
930
|
+
|
|
931
|
+
Eventer.prototype._handleRaceError = function (e, obj, ctx, task) {
|
|
932
|
+
ctx.error_count++;
|
|
933
|
+
this.log('error', `事件执行失败 [${ctx.space}:${ctx.event}] - ${obj.name}`, e);
|
|
934
|
+
|
|
935
|
+
const error_result = {
|
|
936
|
+
_error: true,
|
|
937
|
+
error: e,
|
|
938
|
+
handler: obj.name,
|
|
939
|
+
timestamp: Date.now()
|
|
940
|
+
};
|
|
941
|
+
|
|
942
|
+
ctx.results.push(error_result);
|
|
943
|
+
this._callErrorHandler(e, obj, ctx);
|
|
944
|
+
|
|
945
|
+
return { success: false, error: e, handler: obj.name };
|
|
946
|
+
};
|
|
947
|
+
|
|
948
|
+
Eventer.prototype._runRace = async function (promises) {
|
|
949
|
+
if (promises.length > 0) {
|
|
950
|
+
let race = await Promise.race(promises);
|
|
951
|
+
return race;
|
|
952
|
+
}
|
|
953
|
+
return null;
|
|
954
|
+
};
|
|
955
|
+
|
|
956
|
+
/**
|
|
957
|
+
* 执行单个任务(并行执行时使用)
|
|
958
|
+
* @param {object} config 配置参数
|
|
959
|
+
* @private
|
|
960
|
+
*/
|
|
961
|
+
Eventer.prototype._executeSingleTask = async function (config) {
|
|
962
|
+
const { obj, params, ctx, full_key, arr, idx, proc_results } = config;
|
|
963
|
+
obj.last_executed = Date.now();
|
|
964
|
+
|
|
965
|
+
// 创建任务
|
|
966
|
+
let task_info = this._createParallelTask(obj, full_key);
|
|
967
|
+
|
|
968
|
+
try {
|
|
969
|
+
let result = await obj.func.apply(obj, params);
|
|
970
|
+
this._handleTaskSuccess({ result, obj, ctx, arr, idx, proc_results, task_info });
|
|
971
|
+
} catch (err) {
|
|
972
|
+
this._handleTaskError({ err, obj, ctx, idx, proc_results, task_info });
|
|
973
|
+
}
|
|
974
|
+
};
|
|
975
|
+
|
|
976
|
+
Eventer.prototype._createParallelTask = function (obj, full_key) {
|
|
977
|
+
let task_id = `${obj.name}_${Date.now()}`;
|
|
978
|
+
let cancelled = false;
|
|
979
|
+
const task = {
|
|
980
|
+
id: task_id,
|
|
981
|
+
cancel: () => { cancelled = true; }
|
|
982
|
+
};
|
|
983
|
+
|
|
984
|
+
// 添加到进行中的任务列表(防御性处理重入调用导致 key 已被清理的情况)
|
|
985
|
+
let tasks = this._tasks.get(full_key);
|
|
986
|
+
if (!tasks) {
|
|
987
|
+
tasks = [];
|
|
988
|
+
this._tasks.set(full_key, tasks);
|
|
989
|
+
}
|
|
990
|
+
tasks.push(task);
|
|
991
|
+
|
|
992
|
+
return { task, tasks, cancelled };
|
|
993
|
+
};
|
|
994
|
+
|
|
995
|
+
Eventer.prototype._handleTaskSuccess = function (config) {
|
|
996
|
+
const { result, obj, ctx, arr, idx, proc_results, task_info } = config;
|
|
997
|
+
|
|
998
|
+
// 从进行中的任务列表中移除
|
|
999
|
+
task_info.tasks.splice(task_info.tasks.indexOf(task_info.task), 1);
|
|
1000
|
+
|
|
1001
|
+
if (!task_info.cancelled && !ctx.cancelled) {
|
|
1002
|
+
proc_results[idx] = result;
|
|
1003
|
+
|
|
1004
|
+
// 处理执行次数限制
|
|
1005
|
+
if (obj.times >= 0) {
|
|
1006
|
+
obj.times--;
|
|
1007
|
+
if (obj.times <= 0) {
|
|
1008
|
+
arr.push(obj.name);
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
};
|
|
1013
|
+
|
|
1014
|
+
Eventer.prototype._handleTaskError = function (config) {
|
|
1015
|
+
const { err, obj, ctx, idx, proc_results, task_info } = config;
|
|
1016
|
+
|
|
1017
|
+
// 从进行中的任务列表中移除
|
|
1018
|
+
task_info.tasks.splice(task_info.tasks.indexOf(task_info.task), 1);
|
|
1019
|
+
|
|
1020
|
+
if (!task_info.cancelled && !ctx.cancelled) {
|
|
1021
|
+
const error_result = {
|
|
1022
|
+
_error: true,
|
|
1023
|
+
error: err,
|
|
1024
|
+
handler: obj.name,
|
|
1025
|
+
timestamp: Date.now()
|
|
1026
|
+
};
|
|
1027
|
+
proc_results[idx] = error_result;
|
|
1028
|
+
|
|
1029
|
+
// 全局错误处理器
|
|
1030
|
+
if (this.config.error_handler && typeof this.config.error_handler === 'function') {
|
|
1031
|
+
this.config.error_handler(err, { type: 'handler', handler: obj.name, ctx });
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
};
|
|
1035
|
+
|
|
1036
|
+
/**
|
|
1037
|
+
* 执行事件(支持中间件和命名空间)
|
|
1038
|
+
* @param {string} key 事件关键字,支持space:key格式
|
|
1039
|
+
* @param {object} params 传递参数
|
|
1040
|
+
* @returns {Promise<object>} 返回包含results和cancel方法的对象
|
|
1041
|
+
*/
|
|
1042
|
+
Eventer.prototype.run = async function (key, ...params) {
|
|
1043
|
+
return this._execute(key, { exec_mode: 'sequential' }, ...params);
|
|
1044
|
+
};
|
|
1045
|
+
|
|
1046
|
+
/**
|
|
1047
|
+
* 触发事件
|
|
1048
|
+
* @param {string} key 事件关键,支持space:key格式
|
|
1049
|
+
* @param {object} params 传递参数
|
|
1050
|
+
* @returns {Promise<object>} 返回包含results和cancel方法的对象
|
|
1051
|
+
*/
|
|
1052
|
+
Eventer.prototype.emit = function (key, ...params) {
|
|
1053
|
+
// 内部调用 _execute 方法,但不等待结果
|
|
1054
|
+
try {
|
|
1055
|
+
let result = this._execute(key, { exec_mode: 'sequential' }, ...params);
|
|
1056
|
+
result.catch(e => this.log('error', '事件异步执行失败:', e));
|
|
1057
|
+
return {
|
|
1058
|
+
...result,
|
|
1059
|
+
cancel: () => {
|
|
1060
|
+
try {
|
|
1061
|
+
return result.then(r => r && typeof r.cancel === 'function' && r.cancel());
|
|
1062
|
+
} catch (cancel_error) {
|
|
1063
|
+
this.log('error', `事件取消失败 [${key}]`, cancel_error);
|
|
1064
|
+
return Promise.resolve();
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
};
|
|
1068
|
+
} catch (error) {
|
|
1069
|
+
this.log('error', `事件触发失败 [${key}]`, error);
|
|
1070
|
+
// 返回一个安全的默认结果
|
|
1071
|
+
return {
|
|
1072
|
+
results: [],
|
|
1073
|
+
cancelled: false,
|
|
1074
|
+
cancel: () => { },
|
|
1075
|
+
error: error
|
|
1076
|
+
};
|
|
1077
|
+
}
|
|
1078
|
+
};
|
|
1079
|
+
|
|
1080
|
+
/**
|
|
1081
|
+
* 异步触发事件,按顺序执行等待完成
|
|
1082
|
+
* @param {string} key 事件关键字,支持space:key格式
|
|
1083
|
+
* @param {...any} args 事件参数
|
|
1084
|
+
* @returns {Promise} - 事件触发结果
|
|
1085
|
+
*/
|
|
1086
|
+
Eventer.prototype.emitWait = async function (key, ...args) {
|
|
1087
|
+
try {
|
|
1088
|
+
let result = await this._execute(key, { exec_mode: 'sequential' }, ...args);
|
|
1089
|
+
return result.results || [];
|
|
1090
|
+
} catch (error) {
|
|
1091
|
+
this.log('error', `等待事件触发失败 [${key}]`, error);
|
|
1092
|
+
return [];
|
|
1093
|
+
}
|
|
1094
|
+
};
|
|
1095
|
+
|
|
1096
|
+
/**
|
|
1097
|
+
* 异步触发事件,并发执行不等待
|
|
1098
|
+
* @param {string} key 事件关键字,支持space:key格式
|
|
1099
|
+
* @param {...any} args 事件参数
|
|
1100
|
+
* @returns {boolean} - 是否有监听者
|
|
1101
|
+
*/
|
|
1102
|
+
Eventer.prototype.emitAsync = async function (key, ...args) {
|
|
1103
|
+
try {
|
|
1104
|
+
return this._execAsync(key, args);
|
|
1105
|
+
} catch (global_error) {
|
|
1106
|
+
this.log('error', `异步事件触发失败 [${key}]`, global_error);
|
|
1107
|
+
return false;
|
|
1108
|
+
}
|
|
1109
|
+
};
|
|
1110
|
+
|
|
1111
|
+
Eventer.prototype._execAsync = function (key, args) {
|
|
1112
|
+
// 解析命名空间
|
|
1113
|
+
let parsed = this._parseKey(key);
|
|
1114
|
+
let space = parsed.space;
|
|
1115
|
+
let event_key = parsed.key;
|
|
1116
|
+
let full_key = `${space}:${event_key}`;
|
|
1117
|
+
|
|
1118
|
+
// 获取事件列表
|
|
1119
|
+
let list = this._dict[space] && this._dict[space][event_key];
|
|
1120
|
+
|
|
1121
|
+
if (!list || list.length === 0) {
|
|
1122
|
+
return false;
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
// 立即启动所有监听器,但不等待
|
|
1126
|
+
list.forEach(handler => {
|
|
1127
|
+
this._executeAsyncHandler(handler, args, full_key);
|
|
1128
|
+
});
|
|
1129
|
+
|
|
1130
|
+
return true;
|
|
1131
|
+
};
|
|
1132
|
+
|
|
1133
|
+
Eventer.prototype._executeAsyncHandler = function (handler, args, full_key) {
|
|
1134
|
+
try {
|
|
1135
|
+
// 使用 Promise.resolve 确保异步执行
|
|
1136
|
+
Promise.resolve(handler.func(...args))
|
|
1137
|
+
.catch(error => {
|
|
1138
|
+
this._handleAsyncError(error, full_key, args);
|
|
1139
|
+
});
|
|
1140
|
+
} catch (sync_error) {
|
|
1141
|
+
this._handleSyncError(sync_error, full_key, args);
|
|
1142
|
+
}
|
|
1143
|
+
};
|
|
1144
|
+
|
|
1145
|
+
Eventer.prototype._handleAsyncError = function (error, full_key, args) {
|
|
1146
|
+
// 错误处理 - 记录但不抛出
|
|
1147
|
+
this.log('error', `异步监听器错误 [${full_key}]:`, error);
|
|
1148
|
+
try {
|
|
1149
|
+
this.emit('async:error', error, full_key, args);
|
|
1150
|
+
} catch (error) {
|
|
1151
|
+
this.log('error', '错误事件触发失败 [async:error]', error);
|
|
1152
|
+
}
|
|
1153
|
+
};
|
|
1154
|
+
|
|
1155
|
+
Eventer.prototype._handleSyncError = function (sync_error, full_key, args) {
|
|
1156
|
+
// 同步错误处理
|
|
1157
|
+
this.log('error', `同步监听器错误 [${full_key}]:`, sync_error);
|
|
1158
|
+
try {
|
|
1159
|
+
this.emit('sync:error', sync_error, full_key, args);
|
|
1160
|
+
} catch (error) {
|
|
1161
|
+
this.log('error', '错误事件触发失败 [sync:error]', error);
|
|
1162
|
+
}
|
|
1163
|
+
};
|
|
1164
|
+
|
|
1165
|
+
/**
|
|
1166
|
+
* 异步触发事件,并发执行等待完成
|
|
1167
|
+
* @param {string} key 事件关键字,支持space:key格式
|
|
1168
|
+
* @param {...any} args 事件参数
|
|
1169
|
+
* @returns {Promise<Array>} - 所有监听器的执行结果
|
|
1170
|
+
*/
|
|
1171
|
+
Eventer.prototype.emitAll = async function (key, ...args) {
|
|
1172
|
+
try {
|
|
1173
|
+
let result = await this._execute(key, { exec_mode: 'parallel' }, ...args);
|
|
1174
|
+
return result.results || [];
|
|
1175
|
+
} catch (error) {
|
|
1176
|
+
this.log('error', `并发事件触发失败 [${key}]`, error);
|
|
1177
|
+
return [];
|
|
1178
|
+
}
|
|
1179
|
+
};
|
|
1180
|
+
|
|
1181
|
+
/**
|
|
1182
|
+
* 异步触发事件,竞争执行
|
|
1183
|
+
* @param {string} key 事件关键字,支持space:key格式
|
|
1184
|
+
* @param {...any} args 事件参数
|
|
1185
|
+
* @returns {Promise} - 第一个完成的结果
|
|
1186
|
+
*/
|
|
1187
|
+
Eventer.prototype.emitRace = async function (key, ...args) {
|
|
1188
|
+
try {
|
|
1189
|
+
let result = await this._execute(key, { exec_mode: 'race' }, ...args);
|
|
1190
|
+
return result.race || null;
|
|
1191
|
+
} catch (error) {
|
|
1192
|
+
this.log('error', `竞争事件触发失败 [${key}]`, error);
|
|
1193
|
+
return null;
|
|
1194
|
+
}
|
|
1195
|
+
};
|
|
1196
|
+
|
|
1197
|
+
/**
|
|
1198
|
+
* 异步触发事件,返回第一个有返回值的结果(不阻塞其他监听器)
|
|
1199
|
+
* @param {string} key 事件关键字,支持space:key格式
|
|
1200
|
+
* @param {...any} args 事件参数
|
|
1201
|
+
* @returns {Promise} - 第一个有返回值(非 undefined)的监听器结果
|
|
1202
|
+
* 所有监听器并行执行,返回第一个有返回值(非 undefined)的结果,返回 undefined 的监听器被跳过,其他监听器继续在后台执行不受影响
|
|
1203
|
+
*/
|
|
1204
|
+
Eventer.prototype.emitFirst = async function (key, ...args) {
|
|
1205
|
+
try {
|
|
1206
|
+
let parsed = this._parseKey(key);
|
|
1207
|
+
let space = parsed.space;
|
|
1208
|
+
let event_key = parsed.key;
|
|
1209
|
+
|
|
1210
|
+
let list = this._dict[space] && this._dict[space][event_key];
|
|
1211
|
+
if (!list || list.length === 0) {
|
|
1212
|
+
return undefined;
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
return await new Promise(resolve => {
|
|
1216
|
+
let settled = false;
|
|
1217
|
+
let pending = list.length;
|
|
1218
|
+
|
|
1219
|
+
for (let handler of list) {
|
|
1220
|
+
Promise.resolve(handler.func(...args)).then(result => {
|
|
1221
|
+
if (!settled && result !== undefined) {
|
|
1222
|
+
settled = true;
|
|
1223
|
+
resolve(result);
|
|
1224
|
+
}
|
|
1225
|
+
pending--;
|
|
1226
|
+
if (pending === 0 && !settled) {
|
|
1227
|
+
resolve(undefined);
|
|
1228
|
+
}
|
|
1229
|
+
}).catch(() => {
|
|
1230
|
+
pending--;
|
|
1231
|
+
if (pending === 0 && !settled) {
|
|
1232
|
+
resolve(undefined);
|
|
1233
|
+
}
|
|
1234
|
+
});
|
|
1235
|
+
}
|
|
1236
|
+
});
|
|
1237
|
+
} catch (error) {
|
|
1238
|
+
this.log('error', `首个结果事件触发失败 [${key}]`, error);
|
|
1239
|
+
return undefined;
|
|
1240
|
+
}
|
|
1241
|
+
};
|
|
1242
|
+
|
|
1243
|
+
/**
|
|
1244
|
+
* 异步触发事件,瀑布流执行
|
|
1245
|
+
* @param {string} key 事件关键字,支持space:key格式
|
|
1246
|
+
* @param {*} value 初始值
|
|
1247
|
+
* @param {...any} args 事件参数
|
|
1248
|
+
* @returns {Promise} - 最后一个事件监听者的结果
|
|
1249
|
+
*/
|
|
1250
|
+
Eventer.prototype.emitWaterfall = async function (key, value, ...args) {
|
|
1251
|
+
try {
|
|
1252
|
+
let result = await this._execute(key, {
|
|
1253
|
+
exec_mode: 'waterfall',
|
|
1254
|
+
initial_value: value
|
|
1255
|
+
}, ...args);
|
|
1256
|
+
return result.waterfall || value;
|
|
1257
|
+
} catch (error) {
|
|
1258
|
+
this.log('error', `瀑布流事件触发失败 [${key}]`, error);
|
|
1259
|
+
return value;
|
|
1260
|
+
}
|
|
1261
|
+
};
|
|
1262
|
+
|
|
1263
|
+
/**
|
|
1264
|
+
* 确保命名空间在映射中
|
|
1265
|
+
* @private
|
|
1266
|
+
* @param {string} name 命名空间名称
|
|
1267
|
+
*/
|
|
1268
|
+
Eventer.prototype._ensureNs = function (name) {
|
|
1269
|
+
if (!this._space[name]) {
|
|
1270
|
+
this._space[name] = true;
|
|
1271
|
+
}
|
|
1272
|
+
};
|
|
1273
|
+
|
|
1274
|
+
/**
|
|
1275
|
+
* 执行单个命名空间的事件处理函数
|
|
1276
|
+
* @private
|
|
1277
|
+
* @param {string} name 命名空间名称
|
|
1278
|
+
* @param {string} key 事件关键字
|
|
1279
|
+
* @param {Array} params 事件参数
|
|
1280
|
+
* @returns {object} 包含结果和需要移除的事件名称的对象
|
|
1281
|
+
*/
|
|
1282
|
+
Eventer.prototype._execNsEvents = async function (name, key, params) {
|
|
1283
|
+
let list = this._dict[name][key];
|
|
1284
|
+
const name_results = [];
|
|
1285
|
+
const arr = []; // 存储需要移除的事件
|
|
1286
|
+
|
|
1287
|
+
// 执行事件处理函数
|
|
1288
|
+
for (let i = 0; i < list.length; i++) {
|
|
1289
|
+
try {
|
|
1290
|
+
let obj = list[i];
|
|
1291
|
+
// 执行事件处理函数
|
|
1292
|
+
let result = await obj.func.apply(obj, params);
|
|
1293
|
+
name_results.push(result);
|
|
1294
|
+
|
|
1295
|
+
// 处理执行次数限制
|
|
1296
|
+
if (obj.times >= 0) {
|
|
1297
|
+
obj.times--;
|
|
1298
|
+
if (obj.times <= 0) {
|
|
1299
|
+
arr.push(obj.name);
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
} catch (e) {
|
|
1303
|
+
// 记录错误但不中断执行
|
|
1304
|
+
this.log('error', `事件执行失败 [${name}:${key}] - ${list[i].name}`, e);
|
|
1305
|
+
name_results.push({
|
|
1306
|
+
_error: true,
|
|
1307
|
+
error: e,
|
|
1308
|
+
handler: list[i].name
|
|
1309
|
+
});
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
return { name_results, arr };
|
|
1314
|
+
};
|
|
1315
|
+
|
|
1316
|
+
/**
|
|
1317
|
+
* 移除已执行完的事件
|
|
1318
|
+
* @private
|
|
1319
|
+
* @param {string} name 命名空间名称
|
|
1320
|
+
* @param {string} key 事件关键字
|
|
1321
|
+
* @param {Array} arr 需要移除的事件名称数组
|
|
1322
|
+
*/
|
|
1323
|
+
Eventer.prototype.emitAllNamespaces = async function (key, ...params) {
|
|
1324
|
+
const results = {};
|
|
1325
|
+
// 确保遍历所有命名空间,包括动态创建的
|
|
1326
|
+
for (let name in this._dict) {
|
|
1327
|
+
// 确保命名空间在space映射中
|
|
1328
|
+
this._ensureNs(name);
|
|
1329
|
+
|
|
1330
|
+
// 检查该命名空间下是否存在该事件
|
|
1331
|
+
if (this._dict[name] && this._dict[name][key]) {
|
|
1332
|
+
const { name_results, arr } = await this._execNsEvents(name, key, params);
|
|
1333
|
+
|
|
1334
|
+
// 移除已执行完的事件
|
|
1335
|
+
this._removeEvents(name, key, arr);
|
|
1336
|
+
|
|
1337
|
+
results[name] = name_results;
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
return results;
|
|
1341
|
+
};
|
|
1342
|
+
|
|
1343
|
+
/**
|
|
1344
|
+
* 删除单个事件监听器
|
|
1345
|
+
* @private
|
|
1346
|
+
* @param {Array} events 事件列表
|
|
1347
|
+
* @param {string | number} index_or_name 事件索引或名称
|
|
1348
|
+
* @returns {boolean} 删除成功返回true,否则返回false
|
|
1349
|
+
*/
|
|
1350
|
+
Eventer.prototype._removeSingleEvent = function (events, index_or_name) {
|
|
1351
|
+
if (typeof (index_or_name) === 'number') {
|
|
1352
|
+
// 按索引删除
|
|
1353
|
+
if (index_or_name >= 0 && index_or_name < events.length) {
|
|
1354
|
+
events.splice(index_or_name, 1);
|
|
1355
|
+
return true;
|
|
1356
|
+
}
|
|
1357
|
+
} else {
|
|
1358
|
+
// 根据名称删除事件
|
|
1359
|
+
for (let j = events.length - 1; j >= 0; j--) {
|
|
1360
|
+
if (events[j].name === index_or_name) {
|
|
1361
|
+
events.splice(j, 1);
|
|
1362
|
+
return true;
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1366
|
+
return false;
|
|
1367
|
+
};
|
|
1368
|
+
|
|
1369
|
+
/**
|
|
1370
|
+
* 删除整个事件
|
|
1371
|
+
* @private
|
|
1372
|
+
* @param {string} space 命名空间
|
|
1373
|
+
* @param {string} event_key 事件键
|
|
1374
|
+
* @param {string} full_key 完整事件关键字
|
|
1375
|
+
* @returns {boolean} 删除成功返回true
|
|
1376
|
+
*/
|
|
1377
|
+
Eventer.prototype._removeEntireEvent = function (space, event_key, full_key) {
|
|
1378
|
+
// 安全检查:确保命名空间和事件存在
|
|
1379
|
+
if (!this._dict[space] || !this._dict[space][event_key]) {
|
|
1380
|
+
return false;
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
// 删除整个事件
|
|
1384
|
+
delete this._dict[space][event_key];
|
|
1385
|
+
|
|
1386
|
+
// 清理相关的事件链
|
|
1387
|
+
if (this._chain) {
|
|
1388
|
+
for (let chain_key in this._chain) {
|
|
1389
|
+
if (chain_key === full_key) {
|
|
1390
|
+
delete this._chain[chain_key];
|
|
1391
|
+
} else if (this._chain[chain_key] && Array.isArray(this._chain[chain_key]) &&
|
|
1392
|
+
this._chain[chain_key].includes(full_key)) {
|
|
1393
|
+
delete this._chain[chain_key];
|
|
1394
|
+
}
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1398
|
+
return true;
|
|
1399
|
+
};
|
|
1400
|
+
|
|
1401
|
+
/**
|
|
1402
|
+
* 自动清理空的事件列表和命名空间
|
|
1403
|
+
* @private
|
|
1404
|
+
* @param {string} space 命名空间
|
|
1405
|
+
* @param {string} key 事件关键字
|
|
1406
|
+
* @param {Array} events 事件列表
|
|
1407
|
+
* @param {string | number} index_or_name 事件索引或名称
|
|
1408
|
+
*/
|
|
1409
|
+
Eventer.prototype._autoCleanEvents = function (space, key, events, index_or_name) {
|
|
1410
|
+
if (!this.config.auto_clean) return;
|
|
1411
|
+
|
|
1412
|
+
// 安全检查:确保命名空间存在
|
|
1413
|
+
if (!this._dict[space]) {
|
|
1414
|
+
return;
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1417
|
+
// 清理空的事件列表
|
|
1418
|
+
if (index_or_name && events && events.length === 0) {
|
|
1419
|
+
// 安全检查:确保事件键存在
|
|
1420
|
+
if (this._dict[space][key]) {
|
|
1421
|
+
delete this._dict[space][key];
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1425
|
+
// 如果命名空间为空,则删除命名空间
|
|
1426
|
+
if (this._dict[space] && Object.keys(this._dict[space]).length === 0) {
|
|
1427
|
+
delete this._dict[space];
|
|
1428
|
+
if (this._space && this._space[space]) {
|
|
1429
|
+
delete this._space[space];
|
|
1430
|
+
}
|
|
1431
|
+
}
|
|
1432
|
+
};
|
|
1433
|
+
|
|
1434
|
+
/**
|
|
1435
|
+
* 删除事件
|
|
1436
|
+
* @param {string} key 事件关键字,支持space:key格式
|
|
1437
|
+
* @param {number | string} index_or_name 事件集索引或名称
|
|
1438
|
+
* @returns {boolean} 删除成功返回true,否则返回false
|
|
1439
|
+
*/
|
|
1440
|
+
Eventer.prototype.off = function (key, index_or_name) {
|
|
1441
|
+
// 入参校验
|
|
1442
|
+
if (!key || typeof key !== 'string') {
|
|
1443
|
+
throw new Error('事件关键字必须是非空字符串');
|
|
1444
|
+
}
|
|
1445
|
+
|
|
1446
|
+
// 解析命名空间
|
|
1447
|
+
let parsed = this._parseKey(key);
|
|
1448
|
+
let space = parsed.space;
|
|
1449
|
+
let event_key = parsed.key;
|
|
1450
|
+
let full_key = `${space}:${event_key}`;
|
|
1451
|
+
|
|
1452
|
+
// 检查事件是否存在
|
|
1453
|
+
if (!this._dict[space] || !this._dict[space][event_key]) {
|
|
1454
|
+
return false;
|
|
1455
|
+
}
|
|
1456
|
+
|
|
1457
|
+
let events = this._dict[space][event_key];
|
|
1458
|
+
let removed = false;
|
|
1459
|
+
|
|
1460
|
+
if (index_or_name) {
|
|
1461
|
+
// 删除单个事件
|
|
1462
|
+
removed = this._removeSingleEvent(events, index_or_name);
|
|
1463
|
+
} else {
|
|
1464
|
+
// 删除整个事件
|
|
1465
|
+
removed = this._removeEntireEvent(space, event_key, full_key);
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1468
|
+
// 自动清理
|
|
1469
|
+
if (removed) {
|
|
1470
|
+
this._autoCleanEvents(space, event_key, events, index_or_name);
|
|
1471
|
+
}
|
|
1472
|
+
|
|
1473
|
+
return removed;
|
|
1474
|
+
};
|
|
1475
|
+
|
|
1476
|
+
Eventer.prototype.add = Eventer.prototype.on;
|
|
1477
|
+
Eventer.prototype.del = Eventer.prototype.off;
|
|
1478
|
+
|
|
1479
|
+
/**
|
|
1480
|
+
* 删除命名空间中的所有事件
|
|
1481
|
+
* @param {string} name 命名空间
|
|
1482
|
+
* @returns {boolean} 删除成功返回true,否则返回false
|
|
1483
|
+
*/
|
|
1484
|
+
Eventer.prototype.clearNamespace = function (name) {
|
|
1485
|
+
if (!name || !this._dict[name]) {
|
|
1486
|
+
return false;
|
|
1487
|
+
}
|
|
1488
|
+
delete this._dict[name];
|
|
1489
|
+
delete this._space[name];
|
|
1490
|
+
return true;
|
|
1491
|
+
};
|
|
1492
|
+
|
|
1493
|
+
/**
|
|
1494
|
+
* 获取事件列表
|
|
1495
|
+
* @param {string} key 事件关键字,如果为空则获取所有事件,支持space:key格式
|
|
1496
|
+
* @returns {Array | object} 返回事件列表或所有事件对象
|
|
1497
|
+
*/
|
|
1498
|
+
Eventer.prototype.getEvents = function (key) {
|
|
1499
|
+
if (key) {
|
|
1500
|
+
// 解析命名空间
|
|
1501
|
+
const { space, key: event_key } = this._parseKey(key);
|
|
1502
|
+
return this._dict[space] &&
|
|
1503
|
+
|
|
1504
|
+
this._dict[space][event_key] ? [...this._dict[space][event_key]] : [];
|
|
1505
|
+
}
|
|
1506
|
+
// 返回深拷贝的所有事件
|
|
1507
|
+
const result = {};
|
|
1508
|
+
for (let name in this._dict) {
|
|
1509
|
+
result[name] = {};
|
|
1510
|
+
for (let key in this._dict[name]) {
|
|
1511
|
+
result[name][key] = [...this._dict[name][key]];
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1514
|
+
return result;
|
|
1515
|
+
};
|
|
1516
|
+
|
|
1517
|
+
/**
|
|
1518
|
+
* 获取所有命名空间
|
|
1519
|
+
* @returns {Array} 返回所有命名空间数组
|
|
1520
|
+
*/
|
|
1521
|
+
Eventer.prototype.getNamespace = function () {
|
|
1522
|
+
return Object.keys(this._space);
|
|
1523
|
+
};
|
|
1524
|
+
|
|
1525
|
+
/**
|
|
1526
|
+
* 清空所有事件和资源
|
|
1527
|
+
* @param {boolean} keep_space 是否保留命名空间定义,默认false
|
|
1528
|
+
* @returns {Eventer} 返回当前实例,支持链式调用
|
|
1529
|
+
*/
|
|
1530
|
+
Eventer.prototype.clear = function (keep_space = false) {
|
|
1531
|
+
// 取消所有进行中的任务
|
|
1532
|
+
if (this._tasks) {
|
|
1533
|
+
this._tasks.forEach((tasks, key) => {
|
|
1534
|
+
tasks.forEach(task => {
|
|
1535
|
+
if (task && typeof task.cancel === 'function') {
|
|
1536
|
+
task.cancel();
|
|
1537
|
+
}
|
|
1538
|
+
});
|
|
1539
|
+
});
|
|
1540
|
+
this._tasks.clear();
|
|
1541
|
+
}
|
|
1542
|
+
|
|
1543
|
+
// 清空事件字典
|
|
1544
|
+
this._dict = {};
|
|
1545
|
+
|
|
1546
|
+
// 清空事件链
|
|
1547
|
+
this._chain = {};
|
|
1548
|
+
|
|
1549
|
+
// 清空暂停状态
|
|
1550
|
+
if (this._paused) {
|
|
1551
|
+
this._paused.clear();
|
|
1552
|
+
}
|
|
1553
|
+
if (this._paused_space) {
|
|
1554
|
+
this._paused_space.clear();
|
|
1555
|
+
}
|
|
1556
|
+
this._paused_global = false;
|
|
1557
|
+
|
|
1558
|
+
// 保留命名空间定义
|
|
1559
|
+
if (!keep_space) {
|
|
1560
|
+
this._space = {};
|
|
1561
|
+
// 重新初始化默认命名空间
|
|
1562
|
+
this._space[this.config.default_name] = true;
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
return this;
|
|
1566
|
+
};
|
|
1567
|
+
|
|
1568
|
+
/**
|
|
1569
|
+
* 检查事件是否存在
|
|
1570
|
+
* @param {string} key 事件关键字,支持space:key格式
|
|
1571
|
+
* @param {string} name 事件名称(可选)
|
|
1572
|
+
* @returns {boolean} 事件存在返回true,否则返回false
|
|
1573
|
+
*/
|
|
1574
|
+
Eventer.prototype.has = function (key, name) {
|
|
1575
|
+
// 解析命名空间
|
|
1576
|
+
let parsed = this._parseKey(key);
|
|
1577
|
+
let space = parsed.space;
|
|
1578
|
+
let event_key = parsed.key;
|
|
1579
|
+
|
|
1580
|
+
if (!this._dict[space] || !this._dict[space][event_key]) {
|
|
1581
|
+
return false;
|
|
1582
|
+
}
|
|
1583
|
+
|
|
1584
|
+
if (name) {
|
|
1585
|
+
let list = this._dict[space][event_key];
|
|
1586
|
+
for (let i = 0; i < list.length; i++) {
|
|
1587
|
+
if (list[i].name === name) {
|
|
1588
|
+
return true;
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1591
|
+
return false;
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1594
|
+
return true;
|
|
1595
|
+
};
|
|
1596
|
+
|
|
1597
|
+
/**
|
|
1598
|
+
* 获取事件数量
|
|
1599
|
+
* @param {string} key 事件关键字,如果为空则获取所有事件数量,支持space:key格式或space:*格式
|
|
1600
|
+
* @returns {number} 返回事件数量
|
|
1601
|
+
*/
|
|
1602
|
+
Eventer.prototype.count = function (key) {
|
|
1603
|
+
if (key) {
|
|
1604
|
+
// 解析可能的命名空间模式
|
|
1605
|
+
if (key.endsWith(':*')) {
|
|
1606
|
+
// 统计命名空间下所有事件
|
|
1607
|
+
let space = key.split(':')[0];
|
|
1608
|
+
if (this._dict[space]) {
|
|
1609
|
+
let total = 0;
|
|
1610
|
+
for (let key in this._dict[space]) {
|
|
1611
|
+
total += this._dict[space][key].length;
|
|
1612
|
+
}
|
|
1613
|
+
return total;
|
|
1614
|
+
}
|
|
1615
|
+
return 0;
|
|
1616
|
+
}
|
|
1617
|
+
|
|
1618
|
+
// 解析具体事件
|
|
1619
|
+
const { space, key: event_key } = this._parseKey(key);
|
|
1620
|
+
return this._dict[space] &&
|
|
1621
|
+
|
|
1622
|
+
this._dict[space][event_key] ? this._dict[space][event_key].length : 0;
|
|
1623
|
+
}
|
|
1624
|
+
|
|
1625
|
+
// 统计所有事件
|
|
1626
|
+
let total = 0;
|
|
1627
|
+
for (let name in this._dict) {
|
|
1628
|
+
for (let key in this._dict[name]) {
|
|
1629
|
+
total += this._dict[name][key].length;
|
|
1630
|
+
}
|
|
1631
|
+
}
|
|
1632
|
+
return total;
|
|
1633
|
+
};
|
|
1634
|
+
|
|
1635
|
+
/**
|
|
1636
|
+
* 添加事件中间件
|
|
1637
|
+
* @param {string} type 中间件类型,'before' 或 'after'
|
|
1638
|
+
* @param {Function} middleware 中间件函数,接收ctx参数
|
|
1639
|
+
* @returns {Eventer} 返回当前实例,支持链式调用
|
|
1640
|
+
*/
|
|
1641
|
+
Eventer.prototype.use = function (type, middleware) {
|
|
1642
|
+
if (type !== 'before' && type !== 'after') {
|
|
1643
|
+
throw new Error('中间件类型必须是 "before" 或 "after"');
|
|
1644
|
+
}
|
|
1645
|
+
if (typeof middleware !== 'function') {
|
|
1646
|
+
throw new Error('中间件必须是一个函数');
|
|
1647
|
+
}
|
|
1648
|
+
|
|
1649
|
+
if (!this._middleware[type]) {
|
|
1650
|
+
this._middleware[type] = [];
|
|
1651
|
+
}
|
|
1652
|
+
this._middleware[type].push(middleware);
|
|
1653
|
+
return this;
|
|
1654
|
+
};
|
|
1655
|
+
|
|
1656
|
+
/**
|
|
1657
|
+
* 添加事件链式触发关系
|
|
1658
|
+
* @param {string} from_event 源事件,支持space:key格式
|
|
1659
|
+
* @param {string | Array} to_events 目标事件,可以是单个事件或事件数组
|
|
1660
|
+
* @returns {Eventer} 返回当前实例,支持链式调用
|
|
1661
|
+
*/
|
|
1662
|
+
Eventer.prototype.chain = function (from_event, to_events) {
|
|
1663
|
+
// 入参校验
|
|
1664
|
+
this._validateChainInput(from_event, to_events);
|
|
1665
|
+
|
|
1666
|
+
// 解析源事件
|
|
1667
|
+
let full_from_event = this._getFullEventKey(from_event);
|
|
1668
|
+
|
|
1669
|
+
// 初始化事件链
|
|
1670
|
+
this._initEventChain(full_from_event);
|
|
1671
|
+
|
|
1672
|
+
// 添加目标事件
|
|
1673
|
+
this._addTargetEvents(full_from_event, to_events);
|
|
1674
|
+
|
|
1675
|
+
return this;
|
|
1676
|
+
};
|
|
1677
|
+
|
|
1678
|
+
Eventer.prototype._validateChainInput = function (from_event, to_events) {
|
|
1679
|
+
if (!from_event || typeof from_event !== 'string') {
|
|
1680
|
+
throw new Error('源事件必须是非空字符串');
|
|
1681
|
+
}
|
|
1682
|
+
};
|
|
1683
|
+
|
|
1684
|
+
Eventer.prototype._getFullEventKey = function (event) {
|
|
1685
|
+
const { space, key } = this._parseKey(event);
|
|
1686
|
+
return `${space}:${key}`;
|
|
1687
|
+
};
|
|
1688
|
+
|
|
1689
|
+
Eventer.prototype._initEventChain = function (full_from_event) {
|
|
1690
|
+
if (!this._chain[full_from_event]) {
|
|
1691
|
+
this._chain[full_from_event] = [];
|
|
1692
|
+
}
|
|
1693
|
+
};
|
|
1694
|
+
|
|
1695
|
+
Eventer.prototype._addTargetEvents = function (full_from_event, to_events) {
|
|
1696
|
+
// 确保目标事件是数组
|
|
1697
|
+
let target_events = Array.isArray(to_events) ? to_events : [to_events];
|
|
1698
|
+
|
|
1699
|
+
for (let i = 0; i < target_events.length; i++) {
|
|
1700
|
+
this._addTargetEvent(full_from_event, target_events[i]);
|
|
1701
|
+
}
|
|
1702
|
+
};
|
|
1703
|
+
|
|
1704
|
+
Eventer.prototype._addTargetEvent = function (full_from_event, to_event) {
|
|
1705
|
+
if (typeof to_event !== 'string') {
|
|
1706
|
+
throw new Error('目标事件必须是非空字符串');
|
|
1707
|
+
}
|
|
1708
|
+
|
|
1709
|
+
// 解析目标事件
|
|
1710
|
+
let full_to_event = this._getFullEventKey(to_event);
|
|
1711
|
+
|
|
1712
|
+
// 避免重复添加
|
|
1713
|
+
if (!this._chain[full_from_event].includes(full_to_event)) {
|
|
1714
|
+
this._chain[full_from_event].push(full_to_event);
|
|
1715
|
+
}
|
|
1716
|
+
};
|
|
1717
|
+
|
|
1718
|
+
/**
|
|
1719
|
+
* 移除事件链式触发关系
|
|
1720
|
+
* @param {string} from_event 源事件,支持space:key格式
|
|
1721
|
+
* @param {string | Array} to_events 目标事件,可以是单个事件或事件数组(可选,不提供则移除所有关联)
|
|
1722
|
+
* @returns {Eventer} 返回当前实例,支持链式调用
|
|
1723
|
+
*/
|
|
1724
|
+
Eventer.prototype.unchain = function (from_event, to_events) {
|
|
1725
|
+
// 入参校验
|
|
1726
|
+
if (!from_event || typeof from_event !== 'string') {
|
|
1727
|
+
throw new Error('源事件必须是非空字符串');
|
|
1728
|
+
}
|
|
1729
|
+
|
|
1730
|
+
// 解析源事件
|
|
1731
|
+
const { space: from_space, key: fromkey } = this._parseKey(from_event);
|
|
1732
|
+
let full_from_event = `${from_space}:${fromkey}`;
|
|
1733
|
+
|
|
1734
|
+
// 如果源事件不存在事件链,直接返回
|
|
1735
|
+
if (!this._chain[full_from_event]) {
|
|
1736
|
+
return this;
|
|
1737
|
+
}
|
|
1738
|
+
|
|
1739
|
+
if (to_events) {
|
|
1740
|
+
this._removeTargetEvents(full_from_event, to_events);
|
|
1741
|
+
} else {
|
|
1742
|
+
// 移除整个事件链
|
|
1743
|
+
delete this._chain[full_from_event];
|
|
1744
|
+
}
|
|
1745
|
+
|
|
1746
|
+
return this;
|
|
1747
|
+
};
|
|
1748
|
+
|
|
1749
|
+
Eventer.prototype._removeTargetEvents = function (full_from_event, to_events) {
|
|
1750
|
+
let target_events = Array.isArray(to_events) ? to_events : [to_events];
|
|
1751
|
+
|
|
1752
|
+
for (let i = 0; i < target_events.length; i++) {
|
|
1753
|
+
this._removeTargetEvent(full_from_event, target_events[i]);
|
|
1754
|
+
}
|
|
1755
|
+
|
|
1756
|
+
// 如果事件链为空,则删除整个事件链
|
|
1757
|
+
if (this._chain[full_from_event].length === 0) {
|
|
1758
|
+
delete this._chain[full_from_event];
|
|
1759
|
+
}
|
|
1760
|
+
};
|
|
1761
|
+
|
|
1762
|
+
Eventer.prototype._removeTargetEvent = function (full_from_event, to_event) {
|
|
1763
|
+
if (typeof to_event !== 'string') {
|
|
1764
|
+
throw new Error('目标事件必须是非空字符串');
|
|
1765
|
+
}
|
|
1766
|
+
|
|
1767
|
+
// 解析目标事件
|
|
1768
|
+
const { space: to_space, key: tokey } = this._parseKey(to_event);
|
|
1769
|
+
let full_to_event = `${to_space}:${tokey}`;
|
|
1770
|
+
|
|
1771
|
+
// 检查事件链是否存在
|
|
1772
|
+
if (!this._chain[full_from_event]) {
|
|
1773
|
+
this.log('warn', `事件链不存在: ${full_from_event} -> ${full_to_event}`);
|
|
1774
|
+
return;
|
|
1775
|
+
}
|
|
1776
|
+
|
|
1777
|
+
// 查找并删除事件链
|
|
1778
|
+
let index = this._chain[full_from_event].indexOf(full_to_event);
|
|
1779
|
+
if (index === -1) {
|
|
1780
|
+
this.log('warn', `事件链不存在: ${full_from_event} -> ${full_to_event}`);
|
|
1781
|
+
return;
|
|
1782
|
+
}
|
|
1783
|
+
|
|
1784
|
+
this._chain[full_from_event].splice(index, 1);
|
|
1785
|
+
};
|
|
1786
|
+
|
|
1787
|
+
/**
|
|
1788
|
+
* 获取事件链
|
|
1789
|
+
* @param {string} event 事件关键字,支持space:key格式
|
|
1790
|
+
* @returns {Array} 返回事件链数组
|
|
1791
|
+
*/
|
|
1792
|
+
Eventer.prototype.getChains = function (event) {
|
|
1793
|
+
if (!event) {
|
|
1794
|
+
return Object.keys(this._chain);
|
|
1795
|
+
}
|
|
1796
|
+
|
|
1797
|
+
// 解析事件
|
|
1798
|
+
const { space, key } = this._parseKey(event);
|
|
1799
|
+
let full_event = `${space}:${key}`;
|
|
1800
|
+
|
|
1801
|
+
return this._chain[full_event] ? [...this._chain[full_event]] : [];
|
|
1802
|
+
};
|
|
1803
|
+
|
|
1804
|
+
/**
|
|
1805
|
+
* 触发下一级事件链事件
|
|
1806
|
+
* @private
|
|
1807
|
+
* @param {string} current_event 当前触发的事件
|
|
1808
|
+
* @param {Array} params 传递的参数
|
|
1809
|
+
* @returns {Promise<void>}
|
|
1810
|
+
*/
|
|
1811
|
+
/**
|
|
1812
|
+
* 并行执行事件(提高性能)
|
|
1813
|
+
* @param {string} key 事件关键字,支持space:key格式
|
|
1814
|
+
* @param {object} params 传递参数
|
|
1815
|
+
* @returns {Promise<object>} 返回包含results和cancel方法的对象
|
|
1816
|
+
*/
|
|
1817
|
+
Eventer.prototype.runParallel = async function (key, ...params) {
|
|
1818
|
+
let result = await this._execute(key, {
|
|
1819
|
+
exec_mode: 'parallel',
|
|
1820
|
+
options: params.options
|
|
1821
|
+
}, ...params);
|
|
1822
|
+
return {
|
|
1823
|
+
results: result.results,
|
|
1824
|
+
cancelled: result.cancelled,
|
|
1825
|
+
cancel: result.cancel
|
|
1826
|
+
};
|
|
1827
|
+
};
|
|
1828
|
+
|
|
1829
|
+
/**
|
|
1830
|
+
* 并行触发事件
|
|
1831
|
+
* @param {string} key 事件关键字,支持space:key格式
|
|
1832
|
+
* @param {object} params 传递参数
|
|
1833
|
+
* @returns {Promise<object>} 返回包含results和cancel方法的对象
|
|
1834
|
+
*/
|
|
1835
|
+
Eventer.prototype.emitParallel = function (key, ...params) {
|
|
1836
|
+
// 内部调用 _execute 方法,但不等待结果
|
|
1837
|
+
let result = this._execute(key, {
|
|
1838
|
+
exec_mode: 'parallel',
|
|
1839
|
+
options: params.options
|
|
1840
|
+
}, ...params);
|
|
1841
|
+
result.catch(e => this.log('error', '事件并行执行失败:', e));
|
|
1842
|
+
return {
|
|
1843
|
+
...result,
|
|
1844
|
+
cancel: () => result.then(r => r && typeof r.cancel === 'function' && r.cancel())
|
|
1845
|
+
};
|
|
1846
|
+
};
|
|
1847
|
+
|
|
1848
|
+
/**
|
|
1849
|
+
* 防止内存泄漏警告
|
|
1850
|
+
* @param {number} max_listen 最大监听器数量
|
|
1851
|
+
* @returns {Eventer} 返回当前实例,支持链式调用
|
|
1852
|
+
*/
|
|
1853
|
+
Eventer.prototype.setMaxListeners = function (max_listen) {
|
|
1854
|
+
if (typeof max_listen !== 'number' || max_listen < 0) {
|
|
1855
|
+
throw new Error('最大监听器数量必须是一个非负数');
|
|
1856
|
+
}
|
|
1857
|
+
this._max_listeners = max_listen;
|
|
1858
|
+
return this;
|
|
1859
|
+
};
|
|
1860
|
+
|
|
1861
|
+
/**
|
|
1862
|
+
* 批量添加事件
|
|
1863
|
+
* @param {object} events_map 事件映射对象 { key: [func1, func2...] 或 key: {func, options} }
|
|
1864
|
+
* @returns {Eventer} 返回当前实例,支持链式调用
|
|
1865
|
+
*/
|
|
1866
|
+
Eventer.prototype.onMany = function (events_map) {
|
|
1867
|
+
if (typeof events_map !== 'object' || events_map === null) {
|
|
1868
|
+
throw new Error('事件对象必须是一个非空对象');
|
|
1869
|
+
}
|
|
1870
|
+
|
|
1871
|
+
for (let event_name in events_map) {
|
|
1872
|
+
if (Object.prototype.hasOwnProperty.call(events_map, event_name)) {
|
|
1873
|
+
this.on(event_name, events_map[event_name]);
|
|
1874
|
+
}
|
|
1875
|
+
}
|
|
1876
|
+
return this;
|
|
1877
|
+
};
|
|
1878
|
+
|
|
1879
|
+
// 私有方法
|
|
1880
|
+
|
|
1881
|
+
/**
|
|
1882
|
+
* 解析事件键,提取命名空间和事件键
|
|
1883
|
+
* @param {string} key 事件关键字
|
|
1884
|
+
* @returns {object} 包含space和key的对象
|
|
1885
|
+
* @private
|
|
1886
|
+
*/
|
|
1887
|
+
Eventer.prototype._parseKey = function (key) {
|
|
1888
|
+
let parts = key.split(':');
|
|
1889
|
+
if (parts.length === 1) {
|
|
1890
|
+
// 没有命名空间,使用默认命名空间
|
|
1891
|
+
return {
|
|
1892
|
+
space: this.config.default_name,
|
|
1893
|
+
key: key
|
|
1894
|
+
};
|
|
1895
|
+
} else if (parts.length === 2) {
|
|
1896
|
+
// 有命名空间
|
|
1897
|
+
return {
|
|
1898
|
+
space: parts[0],
|
|
1899
|
+
key: parts[1]
|
|
1900
|
+
};
|
|
1901
|
+
} else {
|
|
1902
|
+
// 多个冒号,将第一个作为命名空间,其余作为事件键
|
|
1903
|
+
return {
|
|
1904
|
+
space: parts[0],
|
|
1905
|
+
key: parts.slice(1).join(':')
|
|
1906
|
+
};
|
|
1907
|
+
}
|
|
1908
|
+
};
|
|
1909
|
+
|
|
1910
|
+
/**
|
|
1911
|
+
* 按优先级对事件列表进行排序
|
|
1912
|
+
* @param {Array} events 事件列表
|
|
1913
|
+
* @private
|
|
1914
|
+
*/
|
|
1915
|
+
Eventer.prototype._sort = function (events) {
|
|
1916
|
+
events.sort((a, b) => a.priority - b.priority);
|
|
1917
|
+
};
|
|
1918
|
+
|
|
1919
|
+
/**
|
|
1920
|
+
* 运行中间件
|
|
1921
|
+
* @param {string} type 中间件类型:'before' 或 'after'
|
|
1922
|
+
* @param {object} ctx 上下文对象
|
|
1923
|
+
* @private
|
|
1924
|
+
*/
|
|
1925
|
+
Eventer.prototype._runMiddleware = async function (type, ctx) {
|
|
1926
|
+
if (!this._middleware || !this._middleware[type] || this._middleware[type].length === 0) return;
|
|
1927
|
+
|
|
1928
|
+
const mwList = this._middleware[type];
|
|
1929
|
+
for (let i = 0; i < mwList.length; i++) {
|
|
1930
|
+
await this._execMiddleware(mwList[i], type, ctx, i);
|
|
1931
|
+
// 如果上下文被取消,则停止执行
|
|
1932
|
+
if (ctx.cancelled) break;
|
|
1933
|
+
}
|
|
1934
|
+
};
|
|
1935
|
+
|
|
1936
|
+
Eventer.prototype._execMiddleware = async function (middleware, type, ctx, idx) {
|
|
1937
|
+
if (middleware && typeof middleware[type] === 'function') {
|
|
1938
|
+
try {
|
|
1939
|
+
await middleware[type].call(this, ctx);
|
|
1940
|
+
} catch (middleware_error) {
|
|
1941
|
+
this._handleMwareError(middleware_error, type, idx, ctx);
|
|
1942
|
+
}
|
|
1943
|
+
}
|
|
1944
|
+
};
|
|
1945
|
+
|
|
1946
|
+
Eventer.prototype._handleMwareError = function (middleware_error, type, index, ctx) {
|
|
1947
|
+
this.log('error', `中间件执行失败 [${type}] - 索引:${index}`, middleware_error);
|
|
1948
|
+
|
|
1949
|
+
// 全局错误处理器
|
|
1950
|
+
if (this.config.error_handler && typeof this.config.error_handler === 'function') {
|
|
1951
|
+
try {
|
|
1952
|
+
this.config.error_handler(middleware_error, {
|
|
1953
|
+
type: 'middleware',
|
|
1954
|
+
stage: type,
|
|
1955
|
+
index: index,
|
|
1956
|
+
ctx
|
|
1957
|
+
});
|
|
1958
|
+
} catch (handler_error) {
|
|
1959
|
+
this.log('error', '全局错误处理器执行失败', handler_error);
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
1962
|
+
};
|
|
1963
|
+
|
|
1964
|
+
/**
|
|
1965
|
+
* 触发下一级事件链
|
|
1966
|
+
* @param {string} current_event 当前事件键
|
|
1967
|
+
* @param {Array} params 参数数组
|
|
1968
|
+
* @private
|
|
1969
|
+
*/
|
|
1970
|
+
Eventer.prototype._triggerChain = async function (current_event, params) {
|
|
1971
|
+
// 获取当前事件的下级事件列表
|
|
1972
|
+
var next_events = this._chain[current_event];
|
|
1973
|
+
if (!next_events || next_events.length === 0) return;
|
|
1974
|
+
|
|
1975
|
+
// 遍历并触发所有下级事件
|
|
1976
|
+
for (var i = 0; i < next_events.length; i++) {
|
|
1977
|
+
await this._triggerChainEvent(next_events[i], current_event, params);
|
|
1978
|
+
}
|
|
1979
|
+
};
|
|
1980
|
+
|
|
1981
|
+
Eventer.prototype._triggerChainEvent = async function (key, current_event, params) {
|
|
1982
|
+
// 避免重复执行当前事件
|
|
1983
|
+
if (key === current_event) return;
|
|
1984
|
+
|
|
1985
|
+
// 创建下级事件的上下文
|
|
1986
|
+
var ctx = this._createChainCtx(key, current_event, params);
|
|
1987
|
+
|
|
1988
|
+
// 执行前置中间件
|
|
1989
|
+
await this._runChainMware('before', ctx);
|
|
1990
|
+
if (ctx.cancelled) return;
|
|
1991
|
+
|
|
1992
|
+
// 触发下级事件
|
|
1993
|
+
await this._executeChainEvent(key, params, ctx);
|
|
1994
|
+
|
|
1995
|
+
// 执行后置中间件
|
|
1996
|
+
await this._runChainMware('after', ctx);
|
|
1997
|
+
|
|
1998
|
+
// 递归触发下级事件的下级事件
|
|
1999
|
+
if (!ctx.cancelled) {
|
|
2000
|
+
await this._triggerChain(ctx.full_event, params);
|
|
2001
|
+
}
|
|
2002
|
+
};
|
|
2003
|
+
|
|
2004
|
+
Eventer.prototype._createChainCtx = function (key, current_event, params) {
|
|
2005
|
+
var { space, key: inner_key } = this._parseKey(key);
|
|
2006
|
+
var full_key = `${space}:${inner_key}`;
|
|
2007
|
+
|
|
2008
|
+
return {
|
|
2009
|
+
space,
|
|
2010
|
+
event: inner_key,
|
|
2011
|
+
full_event: full_key,
|
|
2012
|
+
params,
|
|
2013
|
+
parent_event: current_event,
|
|
2014
|
+
start_time: Date.now(),
|
|
2015
|
+
executed: 0,
|
|
2016
|
+
error_count: 0,
|
|
2017
|
+
cancelled: false,
|
|
2018
|
+
/**
|
|
2019
|
+
* 取消事件执行
|
|
2020
|
+
*/
|
|
2021
|
+
cancel: () => { this.cancelled = true; }
|
|
2022
|
+
};
|
|
2023
|
+
};
|
|
2024
|
+
|
|
2025
|
+
Eventer.prototype._runChainMware = async function (type, ctx) {
|
|
2026
|
+
try {
|
|
2027
|
+
if (type === 'after') {
|
|
2028
|
+
ctx.end_time = Date.now();
|
|
2029
|
+
ctx.duration = ctx.end_time - ctx.start_time;
|
|
2030
|
+
}
|
|
2031
|
+
await this._runMiddleware(type, ctx);
|
|
2032
|
+
} catch (error) {
|
|
2033
|
+
this.log('error', `下级事件${type}中间件执行失败 [${ctx.full_event}]`, error);
|
|
2034
|
+
}
|
|
2035
|
+
};
|
|
2036
|
+
|
|
2037
|
+
Eventer.prototype._executeChainEvent = async function (key, params, ctx) {
|
|
2038
|
+
try {
|
|
2039
|
+
await this.run(key, ...params);
|
|
2040
|
+
} catch (event_error) {
|
|
2041
|
+
this.log('error', `下级事件执行失败 [${ctx.full_event}]`, event_error);
|
|
2042
|
+
}
|
|
2043
|
+
};
|
|
2044
|
+
|
|
2045
|
+
/**
|
|
2046
|
+
* 节流函数
|
|
2047
|
+
* @param {Function} func 要节流的函数
|
|
2048
|
+
* @param {number} limit 节流时间(毫秒)
|
|
2049
|
+
* @returns {Function} 节流后的函数
|
|
2050
|
+
* @private
|
|
2051
|
+
*/
|
|
2052
|
+
Eventer.prototype._throttle = function (func, limit) {
|
|
2053
|
+
let last_func;
|
|
2054
|
+
let last_time = 0;
|
|
2055
|
+
return function () {
|
|
2056
|
+
let ctx = this;
|
|
2057
|
+
let args = arguments;
|
|
2058
|
+
if (!last_time) {
|
|
2059
|
+
func.apply(ctx, args);
|
|
2060
|
+
last_time = Date.now();
|
|
2061
|
+
} else {
|
|
2062
|
+
clearTimeout(last_func);
|
|
2063
|
+
last_func = setTimeout(() => {
|
|
2064
|
+
if ((Date.now() - last_time) >= limit) {
|
|
2065
|
+
func.apply(ctx, args);
|
|
2066
|
+
last_time = Date.now();
|
|
2067
|
+
}
|
|
2068
|
+
}, limit - (Date.now() - last_time));
|
|
2069
|
+
}
|
|
2070
|
+
};
|
|
2071
|
+
};
|
|
2072
|
+
|
|
2073
|
+
/**
|
|
2074
|
+
* 防抖函数
|
|
2075
|
+
* @param {Function} func 要防抖的函数
|
|
2076
|
+
* @param {number} wait 防抖时间(毫秒)
|
|
2077
|
+
* @returns {Function} 防抖后的函数
|
|
2078
|
+
* @private
|
|
2079
|
+
*/
|
|
2080
|
+
Eventer.prototype._debounce = function (func, wait) {
|
|
2081
|
+
let timeout;
|
|
2082
|
+
return function () {
|
|
2083
|
+
let ctx = this;
|
|
2084
|
+
let args = arguments;
|
|
2085
|
+
clearTimeout(timeout);
|
|
2086
|
+
timeout = setTimeout(() => {
|
|
2087
|
+
func.apply(ctx, args);
|
|
2088
|
+
}, wait);
|
|
2089
|
+
};
|
|
2090
|
+
};
|
|
2091
|
+
|
|
2092
|
+
|
|
2093
|
+
/**
|
|
2094
|
+
* 暂停事件执行
|
|
2095
|
+
* @param {string} key 事件关键字或命名空间,支持space:key格式,为空表示全局暂停
|
|
2096
|
+
* @returns {boolean} 是否成功暂停
|
|
2097
|
+
*/
|
|
2098
|
+
Eventer.prototype.pause = function (key = '') {
|
|
2099
|
+
if (!this.config.pause_enabled) {
|
|
2100
|
+
this.log('warn', '暂停功能未启用');
|
|
2101
|
+
return false;
|
|
2102
|
+
}
|
|
2103
|
+
|
|
2104
|
+
if (!key) {
|
|
2105
|
+
return this._pauseGlobal();
|
|
2106
|
+
}
|
|
2107
|
+
|
|
2108
|
+
// 解析关键字
|
|
2109
|
+
let parsed = this._parseKey(key);
|
|
2110
|
+
let space = parsed.space;
|
|
2111
|
+
let event_key = parsed.key;
|
|
2112
|
+
let full_key = `${space}:${event_key}`;
|
|
2113
|
+
|
|
2114
|
+
if (key) {
|
|
2115
|
+
return this._pauseEvent(full_key);
|
|
2116
|
+
} else {
|
|
2117
|
+
return this._pauseNamespace(space);
|
|
2118
|
+
}
|
|
2119
|
+
};
|
|
2120
|
+
|
|
2121
|
+
Eventer.prototype._pauseGlobal = function () {
|
|
2122
|
+
if (this._paused_global) {
|
|
2123
|
+
this.log('warn', '事件总线已处于全局暂停状态');
|
|
2124
|
+
return false;
|
|
2125
|
+
}
|
|
2126
|
+
this._paused_global = true;
|
|
2127
|
+
this.log('info', '事件总线已全局暂停');
|
|
2128
|
+
return true;
|
|
2129
|
+
};
|
|
2130
|
+
|
|
2131
|
+
Eventer.prototype._pauseEvent = function (full_key) {
|
|
2132
|
+
if (this._paused.has(full_key)) {
|
|
2133
|
+
this.log('warn', `事件 '${full_key}' 已处于暂停状态`);
|
|
2134
|
+
return false;
|
|
2135
|
+
}
|
|
2136
|
+
this._paused.add(full_key);
|
|
2137
|
+
this.log('info', `事件 '${full_key}' 已暂停`);
|
|
2138
|
+
return true;
|
|
2139
|
+
};
|
|
2140
|
+
|
|
2141
|
+
Eventer.prototype._pauseNamespace = function (space) {
|
|
2142
|
+
if (this._paused_space.has(space)) {
|
|
2143
|
+
this.log('warn', `命名空间 '${space}' 已处于暂停状态`);
|
|
2144
|
+
return false;
|
|
2145
|
+
}
|
|
2146
|
+
this._paused_space.add(space);
|
|
2147
|
+
this.log('info', `命名空间 '${space}' 已暂停`);
|
|
2148
|
+
return true;
|
|
2149
|
+
};
|
|
2150
|
+
|
|
2151
|
+
/**
|
|
2152
|
+
* 恢复事件执行
|
|
2153
|
+
* @param {string} key 事件关键字或命名空间,支持space:key格式,为空表示恢复全局暂停
|
|
2154
|
+
* @returns {boolean} 是否成功恢复
|
|
2155
|
+
*/
|
|
2156
|
+
Eventer.prototype.resume = function (key = '') {
|
|
2157
|
+
if (!this.config.pause_enabled) {
|
|
2158
|
+
this.log('warn', '暂停功能未启用');
|
|
2159
|
+
return false;
|
|
2160
|
+
}
|
|
2161
|
+
|
|
2162
|
+
if (!key) {
|
|
2163
|
+
return this._resumeGlobal();
|
|
2164
|
+
}
|
|
2165
|
+
|
|
2166
|
+
// 解析关键字
|
|
2167
|
+
let parsed = this._parseKey(key);
|
|
2168
|
+
let space = parsed.space;
|
|
2169
|
+
let event_key = parsed.key;
|
|
2170
|
+
let full_key = `${space}:${event_key}`;
|
|
2171
|
+
|
|
2172
|
+
if (key) {
|
|
2173
|
+
return this._resumeEvent(full_key);
|
|
2174
|
+
} else {
|
|
2175
|
+
return this._resumeNamespace(space);
|
|
2176
|
+
}
|
|
2177
|
+
};
|
|
2178
|
+
|
|
2179
|
+
Eventer.prototype._resumeGlobal = function () {
|
|
2180
|
+
if (!this._paused_global) {
|
|
2181
|
+
this.log('warn', '事件总线未处于全局暂停状态');
|
|
2182
|
+
return false;
|
|
2183
|
+
}
|
|
2184
|
+
this._paused_global = false;
|
|
2185
|
+
this.log('info', '事件总线已恢复运行');
|
|
2186
|
+
return true;
|
|
2187
|
+
};
|
|
2188
|
+
|
|
2189
|
+
Eventer.prototype._resumeEvent = function (full_key) {
|
|
2190
|
+
if (!this._paused.has(full_key)) {
|
|
2191
|
+
this.log('warn', `事件 '${full_key}' 未处于暂停状态`);
|
|
2192
|
+
return false;
|
|
2193
|
+
}
|
|
2194
|
+
this._paused.delete(full_key);
|
|
2195
|
+
this.log('info', `事件 '${full_key}' 已恢复`);
|
|
2196
|
+
return true;
|
|
2197
|
+
};
|
|
2198
|
+
|
|
2199
|
+
Eventer.prototype._resumeNamespace = function (space) {
|
|
2200
|
+
if (!this._paused_space.has(space)) {
|
|
2201
|
+
this.log('warn', `命名空间 '${space}' 未处于暂停状态`);
|
|
2202
|
+
return false;
|
|
2203
|
+
}
|
|
2204
|
+
this._paused_space.delete(space);
|
|
2205
|
+
this.log('info', `命名空间 '${space}' 已恢复`);
|
|
2206
|
+
return true;
|
|
2207
|
+
};
|
|
2208
|
+
|
|
2209
|
+
/**
|
|
2210
|
+
* 检查事件是否被暂停
|
|
2211
|
+
* @param {string} key 事件关键字,支持space:key格式
|
|
2212
|
+
* @returns {boolean} 是否被暂停
|
|
2213
|
+
*/
|
|
2214
|
+
Eventer.prototype.isPaused = function (key) {
|
|
2215
|
+
if (!this.config.pause_enabled) {
|
|
2216
|
+
return false;
|
|
2217
|
+
}
|
|
2218
|
+
|
|
2219
|
+
// 全局暂停检查
|
|
2220
|
+
if (this._paused_global) {
|
|
2221
|
+
return true;
|
|
2222
|
+
}
|
|
2223
|
+
|
|
2224
|
+
// 解析关键字
|
|
2225
|
+
let parsed = this._parseKey(key);
|
|
2226
|
+
let space = parsed.space;
|
|
2227
|
+
let event_key = parsed.key;
|
|
2228
|
+
let full_key = `${space}:${event_key}`;
|
|
2229
|
+
|
|
2230
|
+
// 命名空间暂停检查
|
|
2231
|
+
if (this._paused_space.has(space)) {
|
|
2232
|
+
return true;
|
|
2233
|
+
}
|
|
2234
|
+
|
|
2235
|
+
// 单个事件暂停检查
|
|
2236
|
+
if (this._paused.has(full_key)) {
|
|
2237
|
+
return true;
|
|
2238
|
+
}
|
|
2239
|
+
|
|
2240
|
+
return false;
|
|
2241
|
+
};
|
|
2242
|
+
|
|
2243
|
+
/**
|
|
2244
|
+
* 获取所有暂停的事件和命名空间
|
|
2245
|
+
* @returns {object} 暂停状态信息
|
|
2246
|
+
*/
|
|
2247
|
+
Eventer.prototype.getPausedStatus = function () {
|
|
2248
|
+
return {
|
|
2249
|
+
global_paused: this._paused_global,
|
|
2250
|
+
paused_events: Array.from(this._paused),
|
|
2251
|
+
paused_spaces: Array.from(this._paused_space)
|
|
2252
|
+
};
|
|
2253
|
+
};
|
|
2254
|
+
|
|
2255
|
+
/**
|
|
2256
|
+
* 清除所有暂停状态
|
|
2257
|
+
* @returns {boolean} 是否成功清除
|
|
2258
|
+
*/
|
|
2259
|
+
Eventer.prototype.clearPaused = function () {
|
|
2260
|
+
if (!this.config.pause_enabled) {
|
|
2261
|
+
this.log('warn', '暂停功能未启用');
|
|
2262
|
+
return false;
|
|
2263
|
+
}
|
|
2264
|
+
|
|
2265
|
+
let cleared = false;
|
|
2266
|
+
|
|
2267
|
+
if (this._paused_global) {
|
|
2268
|
+
this._paused_global = false;
|
|
2269
|
+
cleared = true;
|
|
2270
|
+
}
|
|
2271
|
+
|
|
2272
|
+
if (this._paused.size > 0) {
|
|
2273
|
+
this._paused.clear();
|
|
2274
|
+
cleared = true;
|
|
2275
|
+
}
|
|
2276
|
+
|
|
2277
|
+
if (this._paused_space.size > 0) {
|
|
2278
|
+
this._paused_space.clear();
|
|
2279
|
+
cleared = true;
|
|
2280
|
+
}
|
|
2281
|
+
|
|
2282
|
+
if (cleared) {
|
|
2283
|
+
this.log('info', '所有暂停状态已清除');
|
|
2284
|
+
}
|
|
2285
|
+
|
|
2286
|
+
return cleared;
|
|
2287
|
+
};
|
|
2288
|
+
|
|
2289
|
+
let eventer = new Eventer();
|
|
2290
|
+
|
|
2291
|
+
module.exports = {
|
|
2292
|
+
Eventer,
|
|
2293
|
+
eventer
|
|
2294
|
+
};
|