@nimbus2d/core 0.0.1

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.
Files changed (85) hide show
  1. package/dist/index.mjs +18433 -0
  2. package/package.json +39 -0
  3. package/src/base/EventEmitter.js +187 -0
  4. package/src/base/Subsystem.js +183 -0
  5. package/src/base/index.js +6 -0
  6. package/src/core/Application/AppState.js +27 -0
  7. package/src/core/Application/Application.js +480 -0
  8. package/src/core/Application/DefaultConfig.js +63 -0
  9. package/src/core/Application/index.js +7 -0
  10. package/src/core/AssetManager/AssetManager.js +711 -0
  11. package/src/core/AssetManager/AssetTypes.js +108 -0
  12. package/src/core/AssetManager/adapters/IResourceAdapter.js +50 -0
  13. package/src/core/AssetManager/adapters/PixiAdapter.js +90 -0
  14. package/src/core/AssetManager/core/RefCounter.js +167 -0
  15. package/src/core/AssetManager/core/ResourceCache.js +281 -0
  16. package/src/core/AssetManager/core/ResourceEntry.js +191 -0
  17. package/src/core/AssetManager/core/ResourceEventBus.js +127 -0
  18. package/src/core/AssetManager/handlers/IResourceHandler.js +45 -0
  19. package/src/core/AssetManager/index.js +26 -0
  20. package/src/core/AssetManager/plugins/IResourcePlugin.js +56 -0
  21. package/src/core/Camera/Camera.js +534 -0
  22. package/src/core/Camera/CameraTypes.js +59 -0
  23. package/src/core/Camera/index.js +13 -0
  24. package/src/core/ConfigSystem/ConfigLayer.js +230 -0
  25. package/src/core/ConfigSystem/ConfigLayerType.js +31 -0
  26. package/src/core/ConfigSystem/ConfigMerger.js +50 -0
  27. package/src/core/ConfigSystem/ConfigPath.js +96 -0
  28. package/src/core/ConfigSystem/ConfigSystem.js +378 -0
  29. package/src/core/ConfigSystem/ConfigTypes.js +29 -0
  30. package/src/core/ConfigSystem/ConfigWatcher.js +84 -0
  31. package/src/core/ConfigSystem/index.js +19 -0
  32. package/src/core/EventBus/EventBus.js +797 -0
  33. package/src/core/EventBus/Interceptor.js +26 -0
  34. package/src/core/EventBus/PerformanceStats.js +105 -0
  35. package/src/core/EventBus/index.js +7 -0
  36. package/src/core/Lifecycle/Lifecycle.js +265 -0
  37. package/src/core/Lifecycle/LifecycleState.js +31 -0
  38. package/src/core/Lifecycle/index.js +6 -0
  39. package/src/core/Logger/ConsoleHandler.js +55 -0
  40. package/src/core/Logger/LogHandler.js +34 -0
  41. package/src/core/Logger/LogLevel.js +38 -0
  42. package/src/core/Logger/Logger.js +234 -0
  43. package/src/core/Logger/index.js +8 -0
  44. package/src/core/PluginSystem/Plugin.js +156 -0
  45. package/src/core/PluginSystem/PluginEntry.js +102 -0
  46. package/src/core/PluginSystem/PluginState.js +30 -0
  47. package/src/core/PluginSystem/PluginSystem.js +530 -0
  48. package/src/core/PluginSystem/index.js +8 -0
  49. package/src/core/PoolManager/DefaultConfig.js +19 -0
  50. package/src/core/PoolManager/ObjectPool.js +326 -0
  51. package/src/core/PoolManager/PoolManager.js +253 -0
  52. package/src/core/PoolManager/PoolTypes.js +92 -0
  53. package/src/core/PoolManager/index.js +15 -0
  54. package/src/core/SceneManager/FadeTransition.js +64 -0
  55. package/src/core/SceneManager/MaskTransition.js +234 -0
  56. package/src/core/SceneManager/Scene.js +221 -0
  57. package/src/core/SceneManager/SceneManager.js +658 -0
  58. package/src/core/SceneManager/SceneState.js +29 -0
  59. package/src/core/SceneManager/SlideTransition.js +113 -0
  60. package/src/core/SceneManager/Transition.js +102 -0
  61. package/src/core/SceneManager/ZoomTransition.js +119 -0
  62. package/src/core/SceneManager/index.js +12 -0
  63. package/src/core/SpriteGPULayer/SpriteGPULayer.js +321 -0
  64. package/src/core/SpriteGPULayer/SpriteGPULayerTypes.js +49 -0
  65. package/src/core/SpriteGPULayer/index.js +11 -0
  66. package/src/core/Timeline/Clip.js +101 -0
  67. package/src/core/Timeline/DefaultConfig.js +41 -0
  68. package/src/core/Timeline/Easing.js +176 -0
  69. package/src/core/Timeline/Timeline.js +458 -0
  70. package/src/core/Timeline/TimelineTypes.js +89 -0
  71. package/src/core/Timeline/Track.js +202 -0
  72. package/src/core/Timeline/index.js +22 -0
  73. package/src/errors/ConfigError.js +47 -0
  74. package/src/errors/LifecycleError.js +58 -0
  75. package/src/errors/NimbusError.js +43 -0
  76. package/src/errors/PluginError.js +138 -0
  77. package/src/errors/ResourceError.js +166 -0
  78. package/src/errors/SceneError.js +124 -0
  79. package/src/errors/SubsystemError.js +68 -0
  80. package/src/errors/index.js +53 -0
  81. package/src/index.js +86 -0
  82. package/src/types/index.js +141 -0
  83. package/src/utils/MemoryChecker.js +374 -0
  84. package/src/utils/Validator.js +60 -0
  85. package/src/utils/index.js +84 -0
@@ -0,0 +1,797 @@
1
+ // ============================================================================
2
+ // Nimbus2D - EventBus 全局事件总线
3
+ // ----------------------------------------------------------------------------
4
+ // 职责:
5
+ // 1. 重量级设计:on/off/once/emit/emitAsync
6
+ // 2. 命名空间 + 优先级(数字越大越先调用)
7
+ // 3. wildcard 通配符订阅('scene:*'、'*')
8
+ // 4. 可阻止型拦截器(返回 false 阻止传播)
9
+ // 5. 中间件链(Express风格,支持过滤/变换/缓冲)
10
+ // 6. 全局错误处理 + 性能统计
11
+ // 7. 事件传播顺序:拦截器 → 中间件链 → 精确匹配监听器(按优先级降序)→ 通配符监听器
12
+ //
13
+ // 继承关系:
14
+ // EventEmitter → EventBus(基础设施,不被 Lifecycle 调度)
15
+ // ============================================================================
16
+
17
+ import { EventEmitter } from '../../base/EventEmitter.js'
18
+ import { PerformanceStats } from './PerformanceStats.js'
19
+
20
+ class EventBus extends EventEmitter {
21
+ /**
22
+ * 构造函数
23
+ */
24
+ constructor() {
25
+ super()
26
+
27
+ /**
28
+ * 精确匹配监听器映射
29
+ * @type {Map<string, Array<{fn: Function, priority: number, once: boolean}>>}
30
+ */
31
+ this._exactListeners = new Map()
32
+
33
+ /**
34
+ * 通配符监听器列表
35
+ * @type {Array<{pattern: string, fn: Function, priority: number, once: boolean}>}
36
+ */
37
+ this._wildcardListeners = []
38
+
39
+ /**
40
+ * 事件类型拦截器映射
41
+ * @type {Map<string, Array<Function>>}
42
+ */
43
+ this._interceptors = new Map()
44
+
45
+ /**
46
+ * 全局拦截器列表
47
+ * @type {Array<Function>}
48
+ */
49
+ this._globalInterceptors = []
50
+
51
+ /** @type {PerformanceStats} 性能统计 */
52
+ this._stats = new PerformanceStats()
53
+
54
+ /**
55
+ * 中间件列表(按注册顺序执行)
56
+ * 中间件签名:(eventType, data, next) => void
57
+ * data 为信封格式 { payload: any },中间件可修改 payload
58
+ * 不调 next() 阻止事件传播
59
+ * @type {Array<Function>}
60
+ */
61
+ this._middlewares = []
62
+
63
+ /** @type {boolean} 是否已初始化 */
64
+ this._isInitialized = false
65
+
66
+ /**
67
+ * 递归保护标志:正在分发 error 事件时为 true
68
+ * 防止 error 监听器自身抛错导致无限递归
69
+ * @type {boolean}
70
+ * @private
71
+ */
72
+ this._isEmittingError = false
73
+ }
74
+
75
+ // --------------------------------------------------------------------------
76
+ // 监听器管理(重写 EventEmitter 方法)
77
+ // --------------------------------------------------------------------------
78
+
79
+ /**
80
+ * 注册监听器
81
+ * 支持精确匹配('scene:start')和通配符('scene:*'、'*')
82
+ * @param {string} eventType - 事件类型
83
+ * @param {Function} listener - 监听器函数
84
+ * @param {Object} [options={}] - 选项
85
+ * @param {number} [options.priority=0] - 优先级(数字越大越先调用)
86
+ * @returns {Function} 取消注册函数
87
+ */
88
+ on(eventType, listener, options = {}) {
89
+ if (this._destroyed) return () => {}
90
+ if (typeof listener !== 'function') {
91
+ console.warn(`[EventBus] on() 监听器必须是函数: ${eventType}`)
92
+ return () => {}
93
+ }
94
+
95
+ const priority = options.priority ?? 0
96
+ const isWildcard = eventType.includes('*')
97
+
98
+ if (isWildcard) {
99
+ // 通配符监听器
100
+ const entry = { pattern: eventType, fn: listener, priority, once: false }
101
+ this._wildcardListeners.push(entry)
102
+ this._sortWildcardListeners()
103
+ return () => this._removeWildcardListener(entry)
104
+ }
105
+
106
+ // 精确匹配监听器
107
+ if (!this._exactListeners.has(eventType)) {
108
+ this._exactListeners.set(eventType, [])
109
+ }
110
+ const list = this._exactListeners.get(eventType)
111
+ const entry = { fn: listener, priority, once: false }
112
+ list.push(entry)
113
+ this._sortListeners(list)
114
+ this._stats.setListenersCount(this._countAllListeners())
115
+
116
+ return () => this.off(eventType, listener)
117
+ }
118
+
119
+ /**
120
+ * 注册一次性监听器
121
+ * @param {string} eventType - 事件类型
122
+ * @param {Function} listener - 监听器函数
123
+ * @param {Object} [options={}] - 选项
124
+ * @returns {Function} 取消注册函数
125
+ */
126
+ once(eventType, listener, options = {}) {
127
+ if (this._destroyed) return () => {}
128
+ if (typeof listener !== 'function') {
129
+ console.warn(`[EventBus] once() 监听器必须是函数: ${eventType}`)
130
+ return () => {}
131
+ }
132
+
133
+ const priority = options.priority ?? 0
134
+ const isWildcard = eventType.includes('*')
135
+
136
+ if (isWildcard) {
137
+ const entry = { pattern: eventType, fn: listener, priority, once: true }
138
+ this._wildcardListeners.push(entry)
139
+ this._sortWildcardListeners()
140
+ return () => this._removeWildcardListener(entry)
141
+ }
142
+
143
+ if (!this._exactListeners.has(eventType)) {
144
+ this._exactListeners.set(eventType, [])
145
+ }
146
+ const list = this._exactListeners.get(eventType)
147
+ const entry = { fn: listener, priority, once: true }
148
+ list.push(entry)
149
+ this._sortListeners(list)
150
+ this._stats.setListenersCount(this._countAllListeners())
151
+
152
+ return () => this.off(eventType, listener)
153
+ }
154
+
155
+ /**
156
+ * 注销监听器
157
+ * @param {string} eventType - 事件类型
158
+ * @param {Function} listener - 监听器函数
159
+ * @returns {boolean} 是否注销成功
160
+ */
161
+ off(eventType, listener) {
162
+ if (this._destroyed) return false
163
+
164
+ // 尝试从精确匹配中移除
165
+ const list = this._exactListeners.get(eventType)
166
+ if (list) {
167
+ const index = list.findIndex((entry) => entry.fn === listener)
168
+ if (index !== -1) {
169
+ list.splice(index, 1)
170
+ if (list.length === 0) {
171
+ this._exactListeners.delete(eventType)
172
+ }
173
+ this._stats.setListenersCount(this._countAllListeners())
174
+ return true
175
+ }
176
+ }
177
+
178
+ // 尝试从通配符中移除
179
+ const wcIndex = this._wildcardListeners.findIndex((entry) => entry.fn === listener)
180
+ if (wcIndex !== -1) {
181
+ this._wildcardListeners.splice(wcIndex, 1)
182
+ this._stats.setListenersCount(this._countAllListeners())
183
+ return true
184
+ }
185
+
186
+ return false
187
+ }
188
+
189
+ /**
190
+ * 触发事件
191
+ * 执行流程:
192
+ * 1. 检查全局拦截器(返回 false 阻止传播)
193
+ * 2. 检查事件类型拦截器(返回 false 阻止传播)
194
+ * 3. 执行中间件链(按注册顺序,不调 next() 阻止传播)
195
+ * 4. 调用精确匹配监听器(按优先级降序)
196
+ * 5. 调用通配符监听器(scene:* 和 *)
197
+ * @param {string} eventType - 事件类型
198
+ * @param {...*} args - 参数
199
+ * @returns {boolean} true 表示未被拦截器/中间件阻止,false 表示被阻止
200
+ */
201
+ emit(eventType, ...args) {
202
+ if (this._destroyed) return false
203
+
204
+ const startTime = performance.now()
205
+
206
+ // 1. 检查全局拦截器
207
+ for (const interceptor of this._globalInterceptors) {
208
+ try {
209
+ if (interceptor(eventType, ...args) === false) {
210
+ this._stats.recordBlock()
211
+ return false
212
+ }
213
+ } catch (e) {
214
+ console.error(`[EventBus] 全局拦截器执行出错:`, e)
215
+ }
216
+ }
217
+
218
+ // 2. 检查事件类型拦截器
219
+ const typeInterceptors = this._interceptors.get(eventType)
220
+ if (typeInterceptors) {
221
+ for (const interceptor of typeInterceptors) {
222
+ try {
223
+ if (interceptor(...args) === false) {
224
+ this._stats.recordBlock()
225
+ return false
226
+ }
227
+ } catch (e) {
228
+ console.error(`[EventBus] 拦截器执行出错 (${eventType}):`, e)
229
+ }
230
+ }
231
+ }
232
+
233
+ // 3. 中间件链(三期新增)
234
+ if (this._middlewares.length > 0) {
235
+ // 构建信封:始终以数组形式存储参数,确保多参数事件正确分发
236
+ // 中间件可修改 data.payload 数组中的元素(如 data.payload[0] = newValue)
237
+ const data = { payload: args }
238
+ let chainIndex = 0
239
+ let chainCompleted = false
240
+ let chainResult = true
241
+
242
+ const chainNext = () => {
243
+ if (chainIndex < this._middlewares.length) {
244
+ const mw = this._middlewares[chainIndex++]
245
+ try {
246
+ mw(eventType, data, chainNext)
247
+ } catch (e) {
248
+ // 中间件异常:广播 error 事件,标记链终止(异常终止,非主动阻止)
249
+ this._emitError({ error: e, source: 'middleware' })
250
+ chainCompleted = true
251
+ chainResult = false
252
+ return
253
+ }
254
+ } else {
255
+ // 中间件链执行完毕,分发到监听器(展开 payload 数组保持与无中间件路径一致)
256
+ chainCompleted = true
257
+ chainResult = this._dispatchToListeners(eventType, ...data.payload)
258
+ }
259
+ }
260
+ chainNext()
261
+
262
+ // 如果中间件链未完成(某中间件未调 next),返回 false 表示事件被阻止
263
+ if (!chainCompleted) {
264
+ this._stats.recordBlock()
265
+ chainResult = false
266
+ }
267
+
268
+ // 更新性能统计
269
+ const elapsed = performance.now() - startTime
270
+ this._stats.recordEmit(elapsed)
271
+
272
+ return chainResult
273
+ }
274
+
275
+ // 4-5. 无中间件时直接分发(保持原有性能)
276
+ const result = this._dispatchToListeners(eventType, ...args)
277
+
278
+ // 更新性能统计
279
+ const elapsed = performance.now() - startTime
280
+ this._stats.recordEmit(elapsed)
281
+
282
+ return result
283
+ }
284
+
285
+ /**
286
+ * 异步触发事件(等待所有异步监听器完成)
287
+ * 与 emit() 不同的是:拦截器和中间件中的异步操作会被 await,
288
+ * 且所有异步监听器的 Promise 会被等待完成
289
+ * @param {string} eventType - 事件类型
290
+ * @param {...*} args - 参数
291
+ * @returns {Promise<boolean>} true 表示未被拦截器/中间件阻止
292
+ */
293
+ async emitAsync(eventType, ...args) {
294
+ if (this._destroyed) return false
295
+
296
+ const startTime = performance.now()
297
+
298
+ // 1. 检查全局拦截器(异步等待)
299
+ for (const interceptor of this._globalInterceptors) {
300
+ try {
301
+ const result = await interceptor(eventType, ...args)
302
+ if (result === false) {
303
+ this._stats.recordBlock()
304
+ return false
305
+ }
306
+ } catch (e) {
307
+ console.error(`[EventBus] 全局拦截器执行出错:`, e)
308
+ }
309
+ }
310
+
311
+ // 2. 检查事件类型拦截器(异步等待)
312
+ const typeInterceptors = this._interceptors.get(eventType)
313
+ if (typeInterceptors) {
314
+ for (const interceptor of typeInterceptors) {
315
+ try {
316
+ const result = await interceptor(...args)
317
+ if (result === false) {
318
+ this._stats.recordBlock()
319
+ return false
320
+ }
321
+ } catch (e) {
322
+ console.error(`[EventBus] 拦截器执行出错 (${eventType}):`, e)
323
+ }
324
+ }
325
+ }
326
+
327
+ // 3. 中间件链(与 emit() 一致,确保中间件在异步路径也生效)
328
+ if (this._middlewares.length > 0) {
329
+ /** @type {{ payload: any[] }} 信封对象,payload 始终为参数数组 */
330
+ const data = { payload: args }
331
+ let chainIndex = 0
332
+ let chainCompleted = false
333
+ let chainResult = true
334
+
335
+ const chainNext = () => {
336
+ if (chainIndex < this._middlewares.length) {
337
+ const mw = this._middlewares[chainIndex++]
338
+ try {
339
+ mw(eventType, data, chainNext)
340
+ } catch (e) {
341
+ this._emitError({ error: e, source: 'middleware' })
342
+ chainCompleted = true
343
+ chainResult = false
344
+ return
345
+ }
346
+ } else {
347
+ chainCompleted = true
348
+ // 中间件链完成,分发到监听器
349
+ chainResult = this._dispatchToListenersAsync(eventType, data.payload)
350
+ }
351
+ }
352
+ chainNext()
353
+
354
+ // 中间件链未完成(某中间件未调 next())
355
+ if (!chainCompleted) {
356
+ this._stats.recordBlock()
357
+ const elapsed = performance.now() - startTime
358
+ this._stats.recordEmit(elapsed)
359
+ return false
360
+ }
361
+
362
+ // 等待所有异步监听器完成
363
+ if (chainResult && chainResult._promises) {
364
+ await Promise.all(chainResult._promises)
365
+ }
366
+
367
+ const elapsed = performance.now() - startTime
368
+ this._stats.recordEmit(elapsed)
369
+ return chainResult !== false
370
+ }
371
+
372
+ // 4-5. 无中间件时直接异步分发
373
+ const result = this._dispatchToListenersAsync(eventType, args)
374
+
375
+ // 等待所有异步监听器完成
376
+ if (result && result._promises) {
377
+ await Promise.all(result._promises)
378
+ }
379
+
380
+ const elapsed = performance.now() - startTime
381
+ this._stats.recordEmit(elapsed)
382
+ return true
383
+ }
384
+
385
+ // --------------------------------------------------------------------------
386
+ // 拦截器
387
+ // --------------------------------------------------------------------------
388
+
389
+ /**
390
+ * 注册事件类型拦截器
391
+ * @param {string} eventType - 事件类型
392
+ * @param {Function} interceptor - 拦截器 (...args) => boolean(false 阻止传播)
393
+ * @returns {Function} 取消注册函数
394
+ */
395
+ useInterceptor(eventType, interceptor) {
396
+ if (this._destroyed) return () => {}
397
+
398
+ if (!this._interceptors.has(eventType)) {
399
+ this._interceptors.set(eventType, [])
400
+ }
401
+ this._interceptors.get(eventType).push(interceptor)
402
+ this._stats.setInterceptorsCount(this._countAllInterceptors())
403
+
404
+ return () => {
405
+ const list = this._interceptors.get(eventType)
406
+ if (list) {
407
+ const idx = list.indexOf(interceptor)
408
+ if (idx !== -1) list.splice(idx, 1)
409
+ if (list.length === 0) this._interceptors.delete(eventType)
410
+ this._stats.setInterceptorsCount(this._countAllInterceptors())
411
+ }
412
+ }
413
+ }
414
+
415
+ /**
416
+ * 注册全局拦截器(对所有事件生效)
417
+ * @param {Function} interceptor - 拦截器 (eventType, ...args) => boolean
418
+ * @returns {Function} 取消注册函数
419
+ */
420
+ useGlobalInterceptor(interceptor) {
421
+ if (this._destroyed) return () => {}
422
+
423
+ this._globalInterceptors.push(interceptor)
424
+ this._stats.setInterceptorsCount(this._countAllInterceptors())
425
+
426
+ return () => {
427
+ const idx = this._globalInterceptors.indexOf(interceptor)
428
+ if (idx !== -1) this._globalInterceptors.splice(idx, 1)
429
+ this._stats.setInterceptorsCount(this._countAllInterceptors())
430
+ }
431
+ }
432
+
433
+ // --------------------------------------------------------------------------
434
+ // 中间件(三期新增)
435
+ // --------------------------------------------------------------------------
436
+
437
+ /**
438
+ * 注册中间件
439
+ * 中间件在拦截器之后、监听器分发之前执行。
440
+ * Express 风格签名:(eventType, data, next) => void
441
+ * - eventType: 事件类型(字符串)
442
+ * - data: 数据信封 { payload: any[] },payload 始终为参数数组,
443
+ * 中间件可修改数组元素(如 data.payload[0] = newValue)
444
+ * - next: 下一步回调 () => void,不调 next() 阻止事件传播
445
+ *
446
+ * @param {Function} middleware - 中间件函数 (eventType: string, data: { payload: any[] }, next: () => void) => void
447
+ * @returns {Function} 取消注册函数
448
+ */
449
+ use(middleware) {
450
+ if (this._destroyed) return () => {}
451
+
452
+ if (typeof middleware !== 'function') {
453
+ console.warn('[EventBus] use() 中间件必须是函数')
454
+ return () => {}
455
+ }
456
+
457
+ this._middlewares.push(middleware)
458
+
459
+ return () => this.disuse(middleware)
460
+ }
461
+
462
+ /**
463
+ * 移除中间件
464
+ * @param {Function} middleware - 中间件函数
465
+ * @returns {boolean} 是否移除成功
466
+ */
467
+ disuse(middleware) {
468
+ const index = this._middlewares.indexOf(middleware)
469
+ if (index >= 0) {
470
+ this._middlewares.splice(index, 1)
471
+ return true
472
+ }
473
+ return false
474
+ }
475
+
476
+ // --------------------------------------------------------------------------
477
+ // 性能统计
478
+ // --------------------------------------------------------------------------
479
+
480
+ /**
481
+ * 获取性能统计
482
+ * @returns {Object} 统计数据快照
483
+ */
484
+ getStats() {
485
+ return this._stats.getStats()
486
+ }
487
+
488
+ /**
489
+ * 重置性能统计
490
+ */
491
+ resetStats() {
492
+ this._stats.reset()
493
+ }
494
+
495
+ // --------------------------------------------------------------------------
496
+ // 生命周期方法(基础设施,不继承 Subsystem)
497
+ // --------------------------------------------------------------------------
498
+
499
+ /**
500
+ * 初始化(空实现,基础设施无特殊初始化)
501
+ * @returns {Promise<void>}
502
+ */
503
+ async initialize() {
504
+ this._isInitialized = true
505
+ }
506
+
507
+ /**
508
+ * 销毁事件总线,清理所有监听器、拦截器、性能统计
509
+ * @returns {Promise<void>}
510
+ */
511
+ async destroy() {
512
+ if (this._destroyed) return
513
+
514
+ // 先 emit destroyed 事件(super.destroy() 后监听器被清理,emit 无效)
515
+ this.emit('destroyed')
516
+
517
+ this._exactListeners.clear()
518
+ this._wildcardListeners = []
519
+ this._interceptors.clear()
520
+ this._globalInterceptors = []
521
+ this._middlewares = []
522
+ this._stats.reset()
523
+
524
+ // 调用 EventEmitter 基类的 destroy(清理监听器 + 设置 _destroyed = true)
525
+ super.destroy()
526
+ }
527
+
528
+ // --------------------------------------------------------------------------
529
+ // 内部方法
530
+ // --------------------------------------------------------------------------
531
+
532
+ /**
533
+ * 安全分发 error 事件(内部方法)
534
+ * 直接分发给 _exactListeners 和 _wildcardListeners,不走中间件和拦截器,
535
+ * 避免中间件再次抛错导致无限递归。
536
+ * 使用 _isEmittingError 递归保护标志,防止 error 监听器自身抛错导致无限递归。
537
+ *
538
+ * @param {Object} payload - 错误数据 { error: Error, source: string }
539
+ * @private
540
+ */
541
+ _emitError(payload) {
542
+ // 递归保护:正在分发 error 时忽略后续 error,避免无限递归
543
+ if (this._isEmittingError) return
544
+ this._isEmittingError = true
545
+
546
+ try {
547
+ // 1. 分发给精确匹配的 'error' 监听器
548
+ const errorList = this._exactListeners.get('error')
549
+ if (errorList) {
550
+ for (const entry of errorList) {
551
+ try {
552
+ entry.fn(payload)
553
+ } catch {
554
+ // error 监听器自身异常忽略,避免递归
555
+ }
556
+ }
557
+ }
558
+
559
+ // 2. 分发给通配符监听器
560
+ for (const entry of this._wildcardListeners) {
561
+ if (this._matchWildcard(entry.pattern, 'error')) {
562
+ try {
563
+ entry.fn('error', payload)
564
+ } catch {
565
+ // error 监听器自身异常忽略,避免递归
566
+ }
567
+ }
568
+ }
569
+ } finally {
570
+ this._isEmittingError = false
571
+ }
572
+ }
573
+
574
+ /**
575
+ * 分发到监听器(内部方法)
576
+ * 按顺序调用精确匹配监听器和通配符监听器
577
+ * @param {string} eventType - 事件类型
578
+ * @param {...*} args - 参数
579
+ * @returns {boolean} true 表示正常分发完成
580
+ * @private
581
+ */
582
+ _dispatchToListeners(eventType, ...args) {
583
+ // 1. 调用精确匹配监听器(按优先级降序,已排序)
584
+ const exactList = this._exactListeners.get(eventType)
585
+ const onceToRemove = []
586
+
587
+ if (exactList) {
588
+ // 快照防止迭代中修改
589
+ const snapshot = exactList.slice()
590
+ for (const entry of snapshot) {
591
+ try {
592
+ entry.fn(...args)
593
+ } catch (e) {
594
+ // 自动广播全局 error 事件
595
+ this._emitError({ error: e, source: eventType })
596
+ }
597
+ if (entry.once) {
598
+ onceToRemove.push(entry)
599
+ }
600
+ }
601
+
602
+ // 移除 once 监听器
603
+ for (const entry of onceToRemove) {
604
+ const idx = exactList.indexOf(entry)
605
+ if (idx !== -1) exactList.splice(idx, 1)
606
+ }
607
+ if (exactList.length === 0) {
608
+ this._exactListeners.delete(eventType)
609
+ }
610
+ }
611
+
612
+ // 2. 调用通配符监听器
613
+ const wildcardOnceToRemove = []
614
+ for (const entry of this._wildcardListeners) {
615
+ if (this._matchWildcard(entry.pattern, eventType)) {
616
+ try {
617
+ // 通配符监听器第一个参数为事件类型
618
+ entry.fn(eventType, ...args)
619
+ } catch (e) {
620
+ this._emitError({ error: e, source: eventType })
621
+ }
622
+ if (entry.once) {
623
+ wildcardOnceToRemove.push(entry)
624
+ }
625
+ }
626
+ }
627
+
628
+ // 移除通配符 once 监听器
629
+ for (const entry of wildcardOnceToRemove) {
630
+ const idx = this._wildcardListeners.indexOf(entry)
631
+ if (idx !== -1) this._wildcardListeners.splice(idx, 1)
632
+ }
633
+
634
+ return true
635
+ }
636
+
637
+ /**
638
+ * 异步分发到监听器(内部方法,供 emitAsync 使用)
639
+ * 与 _dispatchToListeners 类似,但收集异步监听器的 Promise
640
+ * 返回结果对象包含 _promises 数组,由 emitAsync 等待
641
+ *
642
+ * @param {string} eventType - 事件类型
643
+ * @param {any[]} args - 参数数组
644
+ * @returns {{ _promises: Promise[] }} 包含异步 Promise 列表的结果对象
645
+ * @private
646
+ */
647
+ _dispatchToListenersAsync(eventType, args) {
648
+ /** @type {Promise[]} 异步监听器的 Promise 列表 */
649
+ const promises = []
650
+
651
+ // 1. 调用精确匹配监听器
652
+ const exactList = this._exactListeners.get(eventType)
653
+ const onceToRemove = []
654
+
655
+ if (exactList) {
656
+ const snapshot = exactList.slice()
657
+ for (const entry of snapshot) {
658
+ try {
659
+ const result = entry.fn(...args)
660
+ if (result instanceof Promise) {
661
+ promises.push(result.catch((e) => {
662
+ this._emitError({ error: e, source: eventType })
663
+ }))
664
+ }
665
+ } catch (e) {
666
+ this._emitError({ error: e, source: eventType })
667
+ }
668
+ if (entry.once) onceToRemove.push(entry)
669
+ }
670
+
671
+ // 移除 once 监听器
672
+ for (const entry of onceToRemove) {
673
+ const idx = exactList.indexOf(entry)
674
+ if (idx !== -1) exactList.splice(idx, 1)
675
+ }
676
+ if (exactList.length === 0) {
677
+ this._exactListeners.delete(eventType)
678
+ }
679
+ }
680
+
681
+ // 2. 调用通配符监听器
682
+ const wildcardOnceToRemove = []
683
+ for (const entry of this._wildcardListeners) {
684
+ if (this._matchWildcard(entry.pattern, eventType)) {
685
+ try {
686
+ const result = entry.fn(eventType, ...args)
687
+ if (result instanceof Promise) {
688
+ promises.push(result.catch((e) => {
689
+ this._emitError({ error: e, source: eventType })
690
+ }))
691
+ }
692
+ } catch (e) {
693
+ this._emitError({ error: e, source: eventType })
694
+ }
695
+ if (entry.once) wildcardOnceToRemove.push(entry)
696
+ }
697
+ }
698
+
699
+ // 移除通配符 once 监听器
700
+ for (const entry of wildcardOnceToRemove) {
701
+ const idx = this._wildcardListeners.indexOf(entry)
702
+ if (idx !== -1) this._wildcardListeners.splice(idx, 1)
703
+ }
704
+
705
+ return { _promises: promises }
706
+ }
707
+
708
+ /**
709
+ * 按优先级降序排序监听器列表
710
+ * @param {Array} list - 监听器列表
711
+ * @private
712
+ */
713
+ _sortListeners(list) {
714
+ list.sort((a, b) => b.priority - a.priority)
715
+ }
716
+
717
+ /**
718
+ * 按优先级降序排序通配符监听器
719
+ * @private
720
+ */
721
+ _sortWildcardListeners() {
722
+ this._wildcardListeners.sort((a, b) => b.priority - a.priority)
723
+ }
724
+
725
+ /**
726
+ * 匹配通配符模式
727
+ * 支持场景:
728
+ * '*' → 匹配所有事件
729
+ * 'scene:*' → 匹配 'scene:' 前缀的所有事件
730
+ * 'scene:**' → 匹配 'scene.' 前缀的所有事件
731
+ * @param {string} pattern - 通配符模式
732
+ * @param {string} eventType - 事件类型
733
+ * @returns {boolean} 是否匹配
734
+ * @private
735
+ */
736
+ _matchWildcard(pattern, eventType) {
737
+ if (pattern === '*') return true
738
+
739
+ const colonIdx = pattern.indexOf(':')
740
+ if (colonIdx !== -1) {
741
+ // 'scene:*' 格式:匹配 'scene:' 前缀
742
+ const prefix = pattern.substring(0, colonIdx + 1)
743
+ return eventType.startsWith(prefix)
744
+ }
745
+
746
+ const dotIdx = pattern.indexOf('.**')
747
+ if (dotIdx !== -1) {
748
+ // 'modules.**' 格式:匹配 'modules.' 前缀
749
+ const prefix = pattern.substring(0, dotIdx + 1)
750
+ return eventType.startsWith(prefix)
751
+ }
752
+
753
+ // 其他情况不匹配
754
+ return false
755
+ }
756
+
757
+ /**
758
+ * 移除通配符监听器
759
+ * @param {Object} entry - 监听器条目
760
+ * @private
761
+ */
762
+ _removeWildcardListener(entry) {
763
+ const idx = this._wildcardListeners.indexOf(entry)
764
+ if (idx !== -1) {
765
+ this._wildcardListeners.splice(idx, 1)
766
+ this._stats.setListenersCount(this._countAllListeners())
767
+ }
768
+ }
769
+
770
+ /**
771
+ * 计算所有监听器总数
772
+ * @returns {number}
773
+ * @private
774
+ */
775
+ _countAllListeners() {
776
+ let count = this._wildcardListeners.length
777
+ for (const list of this._exactListeners.values()) {
778
+ count += list.length
779
+ }
780
+ return count
781
+ }
782
+
783
+ /**
784
+ * 计算所有拦截器总数
785
+ * @returns {number}
786
+ * @private
787
+ */
788
+ _countAllInterceptors() {
789
+ let count = this._globalInterceptors.length
790
+ for (const list of this._interceptors.values()) {
791
+ count += list.length
792
+ }
793
+ return count
794
+ }
795
+ }
796
+
797
+ export { EventBus }