@xiacg/exia-event 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +100 -0
- package/dist/exia-event.cjs +565 -0
- package/dist/exia-event.d.ts +109 -0
- package/dist/exia-event.min.cjs +1 -0
- package/dist/exia-event.min.mjs +1 -0
- package/dist/exia-event.mjs +562 -0
- package/package.json +38 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @Description: 事件管理器 - 支持递归保护
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* 事件管理器 - 防止递归调用栈溢出
|
|
6
|
+
*
|
|
7
|
+
* 功能特性:
|
|
8
|
+
* - 递归深度限制防止栈溢出
|
|
9
|
+
* - 完全向后兼容现有API
|
|
10
|
+
*/
|
|
11
|
+
declare class EventManager {
|
|
12
|
+
/**
|
|
13
|
+
* 添加事件监听器
|
|
14
|
+
* @param name - 事件名称
|
|
15
|
+
* @param callback - 回调函数,当事件触发时执行
|
|
16
|
+
* @param target - 可选参数,指定事件监听的目标对象
|
|
17
|
+
* @returns 返回事件ID,可用于移除事件
|
|
18
|
+
*/
|
|
19
|
+
add(name: string, callback: (...args: any[]) => void, target?: any): number;
|
|
20
|
+
/**
|
|
21
|
+
* 添加一个只触发一次的事件监听器
|
|
22
|
+
* @param name - 事件名称
|
|
23
|
+
* @param callback - 事件触发时要执行的回调函数
|
|
24
|
+
* @param target - 可选参数,指定事件监听器的目标对象
|
|
25
|
+
* @returns 返回事件ID,可用于移除事件
|
|
26
|
+
*/
|
|
27
|
+
addOnce(name: string, callback: (...args: any[]) => void, target?: any): number;
|
|
28
|
+
/**
|
|
29
|
+
* 发送事件给所有注册的监听器(带递归保护)
|
|
30
|
+
* @param name - 事件名称
|
|
31
|
+
* @param target - 可选参数,指定目标对象,只有目标对象匹配时才会触发监听器
|
|
32
|
+
* @param args - 传递给监听器回调函数的参数
|
|
33
|
+
*/
|
|
34
|
+
send(name: string, target?: any, ...args: any[]): void;
|
|
35
|
+
/**
|
|
36
|
+
* 通过事件ID移除事件
|
|
37
|
+
* @param eventId 事件ID
|
|
38
|
+
*/
|
|
39
|
+
remove(eventId: number): void;
|
|
40
|
+
/**
|
|
41
|
+
* 移除指定名称的所有事件
|
|
42
|
+
* @param name 事件名称
|
|
43
|
+
*/
|
|
44
|
+
removeByName(name: string): void;
|
|
45
|
+
/**
|
|
46
|
+
* 移除指定目标的所有事件
|
|
47
|
+
* @param target 目标对象
|
|
48
|
+
*/
|
|
49
|
+
removeByTarget(target: any): void;
|
|
50
|
+
/**
|
|
51
|
+
* 移除指定名称和指定目标的事件
|
|
52
|
+
* @param name 事件名称
|
|
53
|
+
* @param target 绑定的目标对象
|
|
54
|
+
*/
|
|
55
|
+
removeByNameAndTarget(name: string, target: any): void;
|
|
56
|
+
/**
|
|
57
|
+
* 清空所有注册的事件
|
|
58
|
+
*/
|
|
59
|
+
clearAll(): void;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @Description: 全局事件
|
|
64
|
+
*/
|
|
65
|
+
declare class GlobalEvent {
|
|
66
|
+
/**
|
|
67
|
+
* 添加一个事件
|
|
68
|
+
* @param name 事件名称
|
|
69
|
+
* @param callback 事件回调
|
|
70
|
+
* @param target 事件目标
|
|
71
|
+
*/
|
|
72
|
+
static add(name: string, callback: (...args: any[]) => void, target?: any): number;
|
|
73
|
+
/**
|
|
74
|
+
* 添加一个只触发一次的事件
|
|
75
|
+
*/
|
|
76
|
+
static addOnce(name: string, callback: (...args: any[]) => void, target?: any): number;
|
|
77
|
+
/**
|
|
78
|
+
* 发送一个事件
|
|
79
|
+
* @param name 事件名称
|
|
80
|
+
* @param args 事件参数
|
|
81
|
+
*/
|
|
82
|
+
static send(name: string, ...args: any[]): void;
|
|
83
|
+
/**
|
|
84
|
+
* 发送一个事件给指定目标
|
|
85
|
+
* @param name 事件名称
|
|
86
|
+
* @param target 事件目标
|
|
87
|
+
* @param args 事件参数
|
|
88
|
+
*/
|
|
89
|
+
static sendToTarget(name: string, target: any, ...args: any[]): void;
|
|
90
|
+
/**
|
|
91
|
+
* 移除一个指定ID的事件
|
|
92
|
+
* @param eventId 事件ID
|
|
93
|
+
*/
|
|
94
|
+
static remove(eventId: number): void;
|
|
95
|
+
static removeByName(name: string): void;
|
|
96
|
+
static removeByTarget(target: any): void;
|
|
97
|
+
/**
|
|
98
|
+
* 通过目标和事件名称批量移除事件
|
|
99
|
+
* @param name 事件名称
|
|
100
|
+
* @param target 事件目标
|
|
101
|
+
*/
|
|
102
|
+
static removeByNameAndTarget(name: string, target: any): void;
|
|
103
|
+
/**
|
|
104
|
+
* 清空所有事件
|
|
105
|
+
*/
|
|
106
|
+
static clearAll(): void;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export { EventManager, GlobalEvent };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var e;!function(e){e[e.Add=1]="Add",e[e.RemoveById=2]="RemoveById",e[e.RemoveByName=3]="RemoveByName",e[e.RemoveByTarget=4]="RemoveByTarget",e[e.RemoveByNameAndTarget=5]="RemoveByNameAndTarget",e[e.ClearAll=6]="ClearAll"}(e||(e={}));class t{constructor(){this.type=e.Add}reset(){this.type=e.Add,this.eventId=0,this.event=null,this.name=null,this.target=null}}class s{constructor(){this.commands=[],this.index=0,this.length=0,this.clearAll=!1}addEvent(s){if(this.index==this.length){let a=new t;a.type=e.Add,a.event=s,this.commands.push(a),this.length++,this.index++}else{let t=this.commands[this.index++];t.type=e.Add,t.event=s}}add(s,a,n,i){if(s!=e.ClearAll)if(this.index==this.length){let e=new t;e.type=s,e.eventId=a,e.name=n,e.target=i,this.commands.push(e),this.length++,this.index++}else{let e=this.commands[this.index++];e.type=s,e.eventId=a,e.name=n,e.target=i}else this.clearAll=!0}forEach(t){if(this.clearAll)t({type:e.ClearAll,eventId:0,event:null,name:null,target:null,reset:null});else{for(let e=0;e<this.index;e++){let s=this.commands[e];t(s),s.reset()}this.index=0}}clear(){this.commands.length=0,this.index=0,this.clearAll=!1,this.length=0}}class a{constructor(){this.once=!1}}class n{constructor(e,t){this._id=0,this._stack=[],this._maxCapacity=64,this._maxCapacity=e,this._msgClass=t}allocate(){if(0==this._stack.length){const e=new this._msgClass;return e.id=++this._id,e}const e=this._stack.pop();return e.id=++this._id,e}recycle(e){return this._maxCapacity>0&&this._stack.length<this._maxCapacity&&(this._stack.push(e),!0)}}class i{constructor(){this.sending_depth=0,this.events=new Map,this.nameToIds=new Map,this.targetToIds=new Map,this.factory=new n(64,a),this.commandManager=new s}add(e,t,s){if(!e)throw new Error("事件名称不能为空");if(!t)throw new Error("回调函数不能为空");let a=this.factory.allocate();return a.name=e,a.callback=t,a.target=s,a.once=!1,this.sending_depth>0?(this.commandManager.addEvent(a),a.id):(this._addEvent(a),a.id)}addOnce(e,t,s){if(!e)throw new Error("事件名称不能为空");if(!t)throw new Error("回调函数不能为空");let a=this.factory.allocate();return a.name=e,a.callback=t,a.target=s,a.once=!0,this.sending_depth>0?(this.commandManager.addEvent(a),a.id):(this._addEvent(a),a.id)}_addEvent(e){this.events.set(e.id,e),this.nameToIds.has(e.name)||this.nameToIds.set(e.name,new Set);this.nameToIds.get(e.name).add(e.id);let t=e.target;t&&(this.targetToIds.has(t)||this.targetToIds.set(t,new Set),this.targetToIds.get(t).add(e.id))}send(t,s,...a){if(this.sending_depth>=20)return console.error("[EventManager] 递归深度超出限制!"),console.error(` 事件名称: "${t}"`),console.error(` 当前深度: ${this.sending_depth}`),console.error(" 最大深度: 20"),void console.error(" 为防止栈溢出,事件执行已被阻止");if(!this.nameToIds.has(t))return;const n=this.nameToIds.get(t);if(0===n.size)return;const i=[],r=[];this.sending_depth++;for(const e of n.values()){if(!this.events.has(e)){i.push(e);continue}let t=this.events.get(e);s&&s!==t.target||(r.push(t),t.once&&i.push(e))}for(const e of r)e.callback(...a);if(this.sending_depth--,0===this.sending_depth){if(i.length>0)for(const e of i)this.remove(e);this.commandManager.forEach(t=>{switch(t.type){case e.Add:this._addEvent(t.event);break;case e.RemoveById:this.remove(t.eventId);break;case e.RemoveByName:this.removeByName(t.name);break;case e.RemoveByTarget:this.removeByTarget(t.target);break;case e.RemoveByNameAndTarget:this.removeByNameAndTarget(t.name,t.target);break;case e.ClearAll:this.clearAll()}})}}remove(t){if(!this.events.has(t))return;if(this.sending_depth>0)return void this.commandManager.add(e.RemoveById,t,null,null);let s=this.events.get(t),a=s.name,n=s.target;this.events.delete(t),this.factory.recycle(s),this.nameToIds.has(a)&&this.nameToIds.get(a).delete(t),n&&this.targetToIds.has(n)&&this.targetToIds.get(n).delete(t)}removeByName(t){if(!this.nameToIds.has(t))return;let s=this.nameToIds.get(t);0!==s.size&&(this.sending_depth>0?this.commandManager.add(e.RemoveByName,null,t,null):(s.forEach(e=>{if(this.events.has(e)){let t=this.events.get(e);t.target&&this.targetToIds.has(t.target)&&this.targetToIds.get(t.target).delete(e),this.events.delete(e),this.factory.recycle(t)}}),this.nameToIds.delete(t)))}removeByTarget(t){if(!this.targetToIds.has(t))return;let s=this.targetToIds.get(t);0!==s.size&&(this.sending_depth>0?this.commandManager.add(e.RemoveByTarget,null,null,t):(s.forEach(e=>{if(this.events.has(e)){let t=this.events.get(e);this.nameToIds.has(t.name)&&this.nameToIds.get(t.name).delete(e),this.events.delete(e),this.factory.recycle(t)}}),this.targetToIds.delete(t)))}removeByNameAndTarget(t,s){if(!this.nameToIds.has(t))return;let a=this.nameToIds.get(t),n=this.targetToIds.get(s);if(0===a.size||!n||0===n.size)return;if(this.sending_depth>0)return void this.commandManager.add(e.RemoveByNameAndTarget,null,t,s);const i=[];if(a.size<n.size?a.forEach(e=>{this.events.get(e).target===s&&i.push(e)}):n.forEach(e=>{this.events.get(e).name===t&&i.push(e)}),i.length>0)for(const e of i)this.remove(e)}clearAll(){if(this.sending_depth>0)this.commandManager.add(e.ClearAll,null,null,null);else{for(const e of this.events.values())this.factory.recycle(e);this.events.clear(),this.nameToIds.clear(),this.targetToIds.clear(),this.commandManager.clear(),this.sending_depth=0}}}class r{static add(e,t,s){return this.event.add(e,t,s)}static addOnce(e,t,s){return this.event.addOnce(e,t,s)}static send(e,...t){this.event.send(e,null,...t)}static sendToTarget(e,t,...s){this.event.send(e,t,...s)}static remove(e){this.event.remove(e)}static removeByName(e){this.event.removeByName(e)}static removeByTarget(e){this.event.removeByTarget(e)}static removeByNameAndTarget(e,t){this.event.removeByNameAndTarget(e,t)}static clearAll(){this.event.clearAll()}}r.event=new i,exports.EventManager=i,exports.GlobalEvent=r;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var e;!function(e){e[e.Add=1]="Add",e[e.RemoveById=2]="RemoveById",e[e.RemoveByName=3]="RemoveByName",e[e.RemoveByTarget=4]="RemoveByTarget",e[e.RemoveByNameAndTarget=5]="RemoveByNameAndTarget",e[e.ClearAll=6]="ClearAll"}(e||(e={}));class t{constructor(){this.type=e.Add}reset(){this.type=e.Add,this.eventId=0,this.event=null,this.name=null,this.target=null}}class s{constructor(){this.commands=[],this.index=0,this.length=0,this.clearAll=!1}addEvent(s){if(this.index==this.length){let a=new t;a.type=e.Add,a.event=s,this.commands.push(a),this.length++,this.index++}else{let t=this.commands[this.index++];t.type=e.Add,t.event=s}}add(s,a,n,i){if(s!=e.ClearAll)if(this.index==this.length){let e=new t;e.type=s,e.eventId=a,e.name=n,e.target=i,this.commands.push(e),this.length++,this.index++}else{let e=this.commands[this.index++];e.type=s,e.eventId=a,e.name=n,e.target=i}else this.clearAll=!0}forEach(t){if(this.clearAll)t({type:e.ClearAll,eventId:0,event:null,name:null,target:null,reset:null});else{for(let e=0;e<this.index;e++){let s=this.commands[e];t(s),s.reset()}this.index=0}}clear(){this.commands.length=0,this.index=0,this.clearAll=!1,this.length=0}}class a{constructor(){this.once=!1}}class n{constructor(e,t){this._id=0,this._stack=[],this._maxCapacity=64,this._maxCapacity=e,this._msgClass=t}allocate(){if(0==this._stack.length){const e=new this._msgClass;return e.id=++this._id,e}const e=this._stack.pop();return e.id=++this._id,e}recycle(e){return this._maxCapacity>0&&this._stack.length<this._maxCapacity&&(this._stack.push(e),!0)}}class i{constructor(){this.sending_depth=0,this.events=new Map,this.nameToIds=new Map,this.targetToIds=new Map,this.factory=new n(64,a),this.commandManager=new s}add(e,t,s){if(!e)throw new Error("事件名称不能为空");if(!t)throw new Error("回调函数不能为空");let a=this.factory.allocate();return a.name=e,a.callback=t,a.target=s,a.once=!1,this.sending_depth>0?(this.commandManager.addEvent(a),a.id):(this._addEvent(a),a.id)}addOnce(e,t,s){if(!e)throw new Error("事件名称不能为空");if(!t)throw new Error("回调函数不能为空");let a=this.factory.allocate();return a.name=e,a.callback=t,a.target=s,a.once=!0,this.sending_depth>0?(this.commandManager.addEvent(a),a.id):(this._addEvent(a),a.id)}_addEvent(e){this.events.set(e.id,e),this.nameToIds.has(e.name)||this.nameToIds.set(e.name,new Set);this.nameToIds.get(e.name).add(e.id);let t=e.target;t&&(this.targetToIds.has(t)||this.targetToIds.set(t,new Set),this.targetToIds.get(t).add(e.id))}send(t,s,...a){if(this.sending_depth>=20)return console.error("[EventManager] 递归深度超出限制!"),console.error(` 事件名称: "${t}"`),console.error(` 当前深度: ${this.sending_depth}`),console.error(" 最大深度: 20"),void console.error(" 为防止栈溢出,事件执行已被阻止");if(!this.nameToIds.has(t))return;const n=this.nameToIds.get(t);if(0===n.size)return;const i=[],h=[];this.sending_depth++;for(const e of n.values()){if(!this.events.has(e)){i.push(e);continue}let t=this.events.get(e);s&&s!==t.target||(h.push(t),t.once&&i.push(e))}for(const e of h)e.callback(...a);if(this.sending_depth--,0===this.sending_depth){if(i.length>0)for(const e of i)this.remove(e);this.commandManager.forEach(t=>{switch(t.type){case e.Add:this._addEvent(t.event);break;case e.RemoveById:this.remove(t.eventId);break;case e.RemoveByName:this.removeByName(t.name);break;case e.RemoveByTarget:this.removeByTarget(t.target);break;case e.RemoveByNameAndTarget:this.removeByNameAndTarget(t.name,t.target);break;case e.ClearAll:this.clearAll()}})}}remove(t){if(!this.events.has(t))return;if(this.sending_depth>0)return void this.commandManager.add(e.RemoveById,t,null,null);let s=this.events.get(t),a=s.name,n=s.target;this.events.delete(t),this.factory.recycle(s),this.nameToIds.has(a)&&this.nameToIds.get(a).delete(t),n&&this.targetToIds.has(n)&&this.targetToIds.get(n).delete(t)}removeByName(t){if(!this.nameToIds.has(t))return;let s=this.nameToIds.get(t);0!==s.size&&(this.sending_depth>0?this.commandManager.add(e.RemoveByName,null,t,null):(s.forEach(e=>{if(this.events.has(e)){let t=this.events.get(e);t.target&&this.targetToIds.has(t.target)&&this.targetToIds.get(t.target).delete(e),this.events.delete(e),this.factory.recycle(t)}}),this.nameToIds.delete(t)))}removeByTarget(t){if(!this.targetToIds.has(t))return;let s=this.targetToIds.get(t);0!==s.size&&(this.sending_depth>0?this.commandManager.add(e.RemoveByTarget,null,null,t):(s.forEach(e=>{if(this.events.has(e)){let t=this.events.get(e);this.nameToIds.has(t.name)&&this.nameToIds.get(t.name).delete(e),this.events.delete(e),this.factory.recycle(t)}}),this.targetToIds.delete(t)))}removeByNameAndTarget(t,s){if(!this.nameToIds.has(t))return;let a=this.nameToIds.get(t),n=this.targetToIds.get(s);if(0===a.size||!n||0===n.size)return;if(this.sending_depth>0)return void this.commandManager.add(e.RemoveByNameAndTarget,null,t,s);const i=[];if(a.size<n.size?a.forEach(e=>{this.events.get(e).target===s&&i.push(e)}):n.forEach(e=>{this.events.get(e).name===t&&i.push(e)}),i.length>0)for(const e of i)this.remove(e)}clearAll(){if(this.sending_depth>0)this.commandManager.add(e.ClearAll,null,null,null);else{for(const e of this.events.values())this.factory.recycle(e);this.events.clear(),this.nameToIds.clear(),this.targetToIds.clear(),this.commandManager.clear(),this.sending_depth=0}}}class h{static add(e,t,s){return this.event.add(e,t,s)}static addOnce(e,t,s){return this.event.addOnce(e,t,s)}static send(e,...t){this.event.send(e,null,...t)}static sendToTarget(e,t,...s){this.event.send(e,t,...s)}static remove(e){this.event.remove(e)}static removeByName(e){this.event.removeByName(e)}static removeByTarget(e){this.event.removeByTarget(e)}static removeByNameAndTarget(e,t){this.event.removeByNameAndTarget(e,t)}static clearAll(){this.event.clearAll()}}h.event=new i;export{i as EventManager,h as GlobalEvent};
|
|
@@ -0,0 +1,562 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @Description: 命令
|
|
3
|
+
*/
|
|
4
|
+
var CommandType;
|
|
5
|
+
(function (CommandType) {
|
|
6
|
+
CommandType[CommandType["Add"] = 1] = "Add";
|
|
7
|
+
CommandType[CommandType["RemoveById"] = 2] = "RemoveById";
|
|
8
|
+
CommandType[CommandType["RemoveByName"] = 3] = "RemoveByName";
|
|
9
|
+
CommandType[CommandType["RemoveByTarget"] = 4] = "RemoveByTarget";
|
|
10
|
+
CommandType[CommandType["RemoveByNameAndTarget"] = 5] = "RemoveByNameAndTarget";
|
|
11
|
+
CommandType[CommandType["ClearAll"] = 6] = "ClearAll";
|
|
12
|
+
})(CommandType || (CommandType = {}));
|
|
13
|
+
/**
|
|
14
|
+
* 命令
|
|
15
|
+
* @internal
|
|
16
|
+
*/
|
|
17
|
+
class Command {
|
|
18
|
+
constructor() {
|
|
19
|
+
this.type = CommandType.Add;
|
|
20
|
+
}
|
|
21
|
+
reset() {
|
|
22
|
+
this.type = CommandType.Add;
|
|
23
|
+
this.eventId = 0;
|
|
24
|
+
this.event = null;
|
|
25
|
+
this.name = null;
|
|
26
|
+
this.target = null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* 命令管理器
|
|
31
|
+
* @internal
|
|
32
|
+
*/
|
|
33
|
+
class CommandManager {
|
|
34
|
+
constructor() {
|
|
35
|
+
this.commands = [];
|
|
36
|
+
this.index = 0;
|
|
37
|
+
this.length = 0;
|
|
38
|
+
this.clearAll = false;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* 添加一个添加事件的命令
|
|
42
|
+
* @param event 事件
|
|
43
|
+
*/
|
|
44
|
+
addEvent(event) {
|
|
45
|
+
if (this.index == this.length) {
|
|
46
|
+
let command = new Command();
|
|
47
|
+
command.type = CommandType.Add;
|
|
48
|
+
command.event = event;
|
|
49
|
+
this.commands.push(command);
|
|
50
|
+
this.length++;
|
|
51
|
+
this.index++;
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
let command = this.commands[this.index++];
|
|
55
|
+
command.type = CommandType.Add;
|
|
56
|
+
command.event = event;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* 添加一个删除事件或者清理所有的命令
|
|
61
|
+
*/
|
|
62
|
+
add(type, eventId, name, target) {
|
|
63
|
+
if (type == CommandType.ClearAll) {
|
|
64
|
+
this.clearAll = true;
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
if (this.index == this.length) {
|
|
68
|
+
let command = new Command();
|
|
69
|
+
command.type = type;
|
|
70
|
+
command.eventId = eventId;
|
|
71
|
+
command.name = name;
|
|
72
|
+
command.target = target;
|
|
73
|
+
this.commands.push(command);
|
|
74
|
+
this.length++;
|
|
75
|
+
this.index++;
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
let command = this.commands[this.index++];
|
|
79
|
+
command.type = type;
|
|
80
|
+
command.eventId = eventId;
|
|
81
|
+
command.name = name;
|
|
82
|
+
command.target = target;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
forEach(callback) {
|
|
86
|
+
if (this.clearAll) {
|
|
87
|
+
callback({
|
|
88
|
+
type: CommandType.ClearAll,
|
|
89
|
+
eventId: 0,
|
|
90
|
+
event: null,
|
|
91
|
+
name: null,
|
|
92
|
+
target: null,
|
|
93
|
+
reset: null,
|
|
94
|
+
});
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
for (let i = 0; i < this.index; i++) {
|
|
98
|
+
let command = this.commands[i];
|
|
99
|
+
callback(command);
|
|
100
|
+
command.reset();
|
|
101
|
+
}
|
|
102
|
+
this.index = 0;
|
|
103
|
+
}
|
|
104
|
+
clear() {
|
|
105
|
+
this.commands.length = 0;
|
|
106
|
+
this.index = 0;
|
|
107
|
+
this.clearAll = false;
|
|
108
|
+
this.length = 0;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** @internal */
|
|
113
|
+
class Event {
|
|
114
|
+
constructor() {
|
|
115
|
+
this.once = false;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** @internal */
|
|
120
|
+
class EventFactory {
|
|
121
|
+
constructor(capacity, objectClass) {
|
|
122
|
+
this._id = 0;
|
|
123
|
+
this._stack = [];
|
|
124
|
+
this._maxCapacity = 64;
|
|
125
|
+
this._maxCapacity = capacity;
|
|
126
|
+
this._msgClass = objectClass;
|
|
127
|
+
}
|
|
128
|
+
allocate() {
|
|
129
|
+
if (this._stack.length == 0) {
|
|
130
|
+
const ret = new this._msgClass();
|
|
131
|
+
ret.id = ++this._id;
|
|
132
|
+
return ret;
|
|
133
|
+
}
|
|
134
|
+
const ret = this._stack.pop();
|
|
135
|
+
// 分配新ID,避免ID重用导致误删
|
|
136
|
+
ret.id = ++this._id;
|
|
137
|
+
return ret;
|
|
138
|
+
}
|
|
139
|
+
recycle(ret) {
|
|
140
|
+
if (this._maxCapacity > 0 && this._stack.length < this._maxCapacity) {
|
|
141
|
+
this._stack.push(ret);
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* @Description: 事件管理器 - 支持递归保护
|
|
150
|
+
*/
|
|
151
|
+
/**
|
|
152
|
+
* 最大递归深度常量
|
|
153
|
+
*/
|
|
154
|
+
const MAX_RECURSION_DEPTH = 20;
|
|
155
|
+
/**
|
|
156
|
+
* 事件管理器 - 防止递归调用栈溢出
|
|
157
|
+
*
|
|
158
|
+
* 功能特性:
|
|
159
|
+
* - 递归深度限制防止栈溢出
|
|
160
|
+
* - 完全向后兼容现有API
|
|
161
|
+
*/
|
|
162
|
+
class EventManager {
|
|
163
|
+
constructor() {
|
|
164
|
+
/**
|
|
165
|
+
* 当前递归发送深度
|
|
166
|
+
* 0 表示没有在发送,> 0 表示正在发送事件
|
|
167
|
+
* @internal
|
|
168
|
+
*/
|
|
169
|
+
this.sending_depth = 0;
|
|
170
|
+
/**
|
|
171
|
+
* 注册的所有事件 事件ID -> 事件
|
|
172
|
+
* @internal
|
|
173
|
+
*/
|
|
174
|
+
this.events = new Map();
|
|
175
|
+
/**
|
|
176
|
+
* 事件名称 -> 事件ID集合
|
|
177
|
+
* @internal
|
|
178
|
+
*/
|
|
179
|
+
this.nameToIds = new Map();
|
|
180
|
+
/**
|
|
181
|
+
* 事件目标 -> 事件ID集合
|
|
182
|
+
* @internal
|
|
183
|
+
*/
|
|
184
|
+
this.targetToIds = new Map();
|
|
185
|
+
/**
|
|
186
|
+
* 事件工厂
|
|
187
|
+
* @internal
|
|
188
|
+
*/
|
|
189
|
+
this.factory = new EventFactory(64, Event);
|
|
190
|
+
/**
|
|
191
|
+
* 命令管理器
|
|
192
|
+
* @internal
|
|
193
|
+
*/
|
|
194
|
+
this.commandManager = new CommandManager();
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* 添加事件监听器
|
|
198
|
+
* @param name - 事件名称
|
|
199
|
+
* @param callback - 回调函数,当事件触发时执行
|
|
200
|
+
* @param target - 可选参数,指定事件监听的目标对象
|
|
201
|
+
* @returns 返回事件ID,可用于移除事件
|
|
202
|
+
*/
|
|
203
|
+
add(name, callback, target) {
|
|
204
|
+
if (!name) {
|
|
205
|
+
throw new Error("事件名称不能为空");
|
|
206
|
+
}
|
|
207
|
+
if (!callback) {
|
|
208
|
+
throw new Error("回调函数不能为空");
|
|
209
|
+
}
|
|
210
|
+
let event = this.factory.allocate();
|
|
211
|
+
event.name = name;
|
|
212
|
+
event.callback = callback;
|
|
213
|
+
event.target = target;
|
|
214
|
+
event.once = false;
|
|
215
|
+
if (this.sending_depth > 0) {
|
|
216
|
+
this.commandManager.addEvent(event);
|
|
217
|
+
return event.id;
|
|
218
|
+
}
|
|
219
|
+
this._addEvent(event);
|
|
220
|
+
return event.id;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* 添加一个只触发一次的事件监听器
|
|
224
|
+
* @param name - 事件名称
|
|
225
|
+
* @param callback - 事件触发时要执行的回调函数
|
|
226
|
+
* @param target - 可选参数,指定事件监听器的目标对象
|
|
227
|
+
* @returns 返回事件ID,可用于移除事件
|
|
228
|
+
*/
|
|
229
|
+
addOnce(name, callback, target) {
|
|
230
|
+
if (!name) {
|
|
231
|
+
throw new Error("事件名称不能为空");
|
|
232
|
+
}
|
|
233
|
+
if (!callback) {
|
|
234
|
+
throw new Error("回调函数不能为空");
|
|
235
|
+
}
|
|
236
|
+
let event = this.factory.allocate();
|
|
237
|
+
event.name = name;
|
|
238
|
+
event.callback = callback;
|
|
239
|
+
event.target = target;
|
|
240
|
+
event.once = true;
|
|
241
|
+
if (this.sending_depth > 0) {
|
|
242
|
+
this.commandManager.addEvent(event);
|
|
243
|
+
return event.id;
|
|
244
|
+
}
|
|
245
|
+
this._addEvent(event);
|
|
246
|
+
return event.id;
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* 添加事件内部方法
|
|
250
|
+
* @param event 事件对象
|
|
251
|
+
* @internal
|
|
252
|
+
*/
|
|
253
|
+
_addEvent(event) {
|
|
254
|
+
this.events.set(event.id, event);
|
|
255
|
+
if (!this.nameToIds.has(event.name)) {
|
|
256
|
+
this.nameToIds.set(event.name, new Set());
|
|
257
|
+
}
|
|
258
|
+
const ids = this.nameToIds.get(event.name);
|
|
259
|
+
ids.add(event.id);
|
|
260
|
+
let target = event.target;
|
|
261
|
+
if (target) {
|
|
262
|
+
if (!this.targetToIds.has(target)) {
|
|
263
|
+
this.targetToIds.set(target, new Set());
|
|
264
|
+
}
|
|
265
|
+
this.targetToIds.get(target).add(event.id);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* 发送事件给所有注册的监听器(带递归保护)
|
|
270
|
+
* @param name - 事件名称
|
|
271
|
+
* @param target - 可选参数,指定目标对象,只有目标对象匹配时才会触发监听器
|
|
272
|
+
* @param args - 传递给监听器回调函数的参数
|
|
273
|
+
*/
|
|
274
|
+
send(name, target, ...args) {
|
|
275
|
+
// 递归深度保护:阻止超过限制的执行并报告错误
|
|
276
|
+
if (this.sending_depth >= MAX_RECURSION_DEPTH) {
|
|
277
|
+
console.error(`[EventManager] 递归深度超出限制!`);
|
|
278
|
+
console.error(` 事件名称: "${name}"`);
|
|
279
|
+
console.error(` 当前深度: ${this.sending_depth}`);
|
|
280
|
+
console.error(` 最大深度: ${MAX_RECURSION_DEPTH}`);
|
|
281
|
+
console.error(` 为防止栈溢出,事件执行已被阻止`);
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
if (!this.nameToIds.has(name)) {
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
const eventIds = this.nameToIds.get(name);
|
|
288
|
+
if (eventIds.size === 0) {
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
// 使用局部变量,避免嵌套调用时互相污染
|
|
292
|
+
const needRemoveIds = [];
|
|
293
|
+
const triggerList = [];
|
|
294
|
+
// 增加递归深度
|
|
295
|
+
this.sending_depth++;
|
|
296
|
+
// 构建触发列表
|
|
297
|
+
for (const eventId of eventIds.values()) {
|
|
298
|
+
if (!this.events.has(eventId)) {
|
|
299
|
+
needRemoveIds.push(eventId);
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
let event = this.events.get(eventId);
|
|
303
|
+
if (!target || target === event.target) {
|
|
304
|
+
triggerList.push(event);
|
|
305
|
+
if (event.once) {
|
|
306
|
+
needRemoveIds.push(eventId);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
// 同步触发事件
|
|
311
|
+
for (const event of triggerList) {
|
|
312
|
+
event.callback(...args);
|
|
313
|
+
}
|
|
314
|
+
// 减少递归深度
|
|
315
|
+
this.sending_depth--;
|
|
316
|
+
// 只在最外层执行清理工作
|
|
317
|
+
if (this.sending_depth === 0) {
|
|
318
|
+
// 清理 once 事件
|
|
319
|
+
if (needRemoveIds.length > 0) {
|
|
320
|
+
for (const id of needRemoveIds) {
|
|
321
|
+
this.remove(id);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
// 处理命令队列
|
|
325
|
+
this.commandManager.forEach((command) => {
|
|
326
|
+
switch (command.type) {
|
|
327
|
+
case CommandType.Add:
|
|
328
|
+
this._addEvent(command.event);
|
|
329
|
+
break;
|
|
330
|
+
case CommandType.RemoveById:
|
|
331
|
+
this.remove(command.eventId);
|
|
332
|
+
break;
|
|
333
|
+
case CommandType.RemoveByName:
|
|
334
|
+
this.removeByName(command.name);
|
|
335
|
+
break;
|
|
336
|
+
case CommandType.RemoveByTarget:
|
|
337
|
+
this.removeByTarget(command.target);
|
|
338
|
+
break;
|
|
339
|
+
case CommandType.RemoveByNameAndTarget:
|
|
340
|
+
this.removeByNameAndTarget(command.name, command.target);
|
|
341
|
+
break;
|
|
342
|
+
case CommandType.ClearAll:
|
|
343
|
+
this.clearAll();
|
|
344
|
+
break;
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* 通过事件ID移除事件
|
|
351
|
+
* @param eventId 事件ID
|
|
352
|
+
*/
|
|
353
|
+
remove(eventId) {
|
|
354
|
+
if (!this.events.has(eventId)) {
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
if (this.sending_depth > 0) {
|
|
358
|
+
this.commandManager.add(CommandType.RemoveById, eventId, null, null);
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
let event = this.events.get(eventId);
|
|
362
|
+
let name = event.name;
|
|
363
|
+
let target = event.target;
|
|
364
|
+
this.events.delete(eventId);
|
|
365
|
+
this.factory.recycle(event);
|
|
366
|
+
if (this.nameToIds.has(name)) {
|
|
367
|
+
this.nameToIds.get(name).delete(eventId);
|
|
368
|
+
}
|
|
369
|
+
if (target && this.targetToIds.has(target)) {
|
|
370
|
+
this.targetToIds.get(target).delete(eventId);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* 移除指定名称的所有事件
|
|
375
|
+
* @param name 事件名称
|
|
376
|
+
*/
|
|
377
|
+
removeByName(name) {
|
|
378
|
+
if (!this.nameToIds.has(name)) {
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
let eventIds = this.nameToIds.get(name);
|
|
382
|
+
if (eventIds.size === 0) {
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
if (this.sending_depth > 0) {
|
|
386
|
+
this.commandManager.add(CommandType.RemoveByName, null, name, null);
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
eventIds.forEach((eventId) => {
|
|
390
|
+
if (this.events.has(eventId)) {
|
|
391
|
+
let event = this.events.get(eventId);
|
|
392
|
+
if (event.target && this.targetToIds.has(event.target)) {
|
|
393
|
+
this.targetToIds.get(event.target).delete(eventId);
|
|
394
|
+
}
|
|
395
|
+
this.events.delete(eventId);
|
|
396
|
+
this.factory.recycle(event);
|
|
397
|
+
}
|
|
398
|
+
});
|
|
399
|
+
this.nameToIds.delete(name);
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* 移除指定目标的所有事件
|
|
403
|
+
* @param target 目标对象
|
|
404
|
+
*/
|
|
405
|
+
removeByTarget(target) {
|
|
406
|
+
if (!this.targetToIds.has(target)) {
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
let eventIds = this.targetToIds.get(target);
|
|
410
|
+
if (eventIds.size === 0) {
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
if (this.sending_depth > 0) {
|
|
414
|
+
this.commandManager.add(CommandType.RemoveByTarget, null, null, target);
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
eventIds.forEach((eventId) => {
|
|
418
|
+
if (this.events.has(eventId)) {
|
|
419
|
+
let event = this.events.get(eventId);
|
|
420
|
+
if (this.nameToIds.has(event.name)) {
|
|
421
|
+
this.nameToIds.get(event.name).delete(eventId);
|
|
422
|
+
}
|
|
423
|
+
this.events.delete(eventId);
|
|
424
|
+
this.factory.recycle(event);
|
|
425
|
+
}
|
|
426
|
+
});
|
|
427
|
+
this.targetToIds.delete(target);
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* 移除指定名称和指定目标的事件
|
|
431
|
+
* @param name 事件名称
|
|
432
|
+
* @param target 绑定的目标对象
|
|
433
|
+
*/
|
|
434
|
+
removeByNameAndTarget(name, target) {
|
|
435
|
+
if (!this.nameToIds.has(name)) {
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
438
|
+
let nameIds = this.nameToIds.get(name);
|
|
439
|
+
let targetIds = this.targetToIds.get(target);
|
|
440
|
+
// 检查targetIds是否存在,避免NPE
|
|
441
|
+
if (nameIds.size === 0 || !targetIds || targetIds.size === 0) {
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
if (this.sending_depth > 0) {
|
|
445
|
+
this.commandManager.add(CommandType.RemoveByNameAndTarget, null, name, target);
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
// 使用局部变量
|
|
449
|
+
const needRemoveIds = [];
|
|
450
|
+
if (nameIds.size < targetIds.size) {
|
|
451
|
+
nameIds.forEach((eventId) => {
|
|
452
|
+
let event = this.events.get(eventId);
|
|
453
|
+
if (event.target === target) {
|
|
454
|
+
needRemoveIds.push(eventId);
|
|
455
|
+
}
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
else {
|
|
459
|
+
targetIds.forEach((eventId) => {
|
|
460
|
+
let event = this.events.get(eventId);
|
|
461
|
+
if (event.name === name) {
|
|
462
|
+
needRemoveIds.push(eventId);
|
|
463
|
+
}
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
if (needRemoveIds.length > 0) {
|
|
467
|
+
for (const id of needRemoveIds) {
|
|
468
|
+
this.remove(id);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* 清空所有注册的事件
|
|
474
|
+
*/
|
|
475
|
+
clearAll() {
|
|
476
|
+
if (this.sending_depth > 0) {
|
|
477
|
+
this.commandManager.add(CommandType.ClearAll, null, null, null);
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
for (const event of this.events.values()) {
|
|
481
|
+
this.factory.recycle(event);
|
|
482
|
+
}
|
|
483
|
+
this.events.clear();
|
|
484
|
+
this.nameToIds.clear();
|
|
485
|
+
this.targetToIds.clear();
|
|
486
|
+
this.commandManager.clear();
|
|
487
|
+
// 清理递归保护相关状态
|
|
488
|
+
this.sending_depth = 0;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* @Description: 全局事件
|
|
494
|
+
*/
|
|
495
|
+
class GlobalEvent {
|
|
496
|
+
/**
|
|
497
|
+
* 添加一个事件
|
|
498
|
+
* @param name 事件名称
|
|
499
|
+
* @param callback 事件回调
|
|
500
|
+
* @param target 事件目标
|
|
501
|
+
*/
|
|
502
|
+
static add(name, callback, target) {
|
|
503
|
+
return this.event.add(name, callback, target);
|
|
504
|
+
}
|
|
505
|
+
/**
|
|
506
|
+
* 添加一个只触发一次的事件
|
|
507
|
+
*/
|
|
508
|
+
static addOnce(name, callback, target) {
|
|
509
|
+
return this.event.addOnce(name, callback, target);
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* 发送一个事件
|
|
513
|
+
* @param name 事件名称
|
|
514
|
+
* @param args 事件参数
|
|
515
|
+
*/
|
|
516
|
+
static send(name, ...args) {
|
|
517
|
+
this.event.send(name, null, ...args);
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* 发送一个事件给指定目标
|
|
521
|
+
* @param name 事件名称
|
|
522
|
+
* @param target 事件目标
|
|
523
|
+
* @param args 事件参数
|
|
524
|
+
*/
|
|
525
|
+
static sendToTarget(name, target, ...args) {
|
|
526
|
+
this.event.send(name, target, ...args);
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
529
|
+
* 移除一个指定ID的事件
|
|
530
|
+
* @param eventId 事件ID
|
|
531
|
+
*/
|
|
532
|
+
static remove(eventId) {
|
|
533
|
+
this.event.remove(eventId);
|
|
534
|
+
}
|
|
535
|
+
static removeByName(name) {
|
|
536
|
+
this.event.removeByName(name);
|
|
537
|
+
}
|
|
538
|
+
static removeByTarget(target) {
|
|
539
|
+
this.event.removeByTarget(target);
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* 通过目标和事件名称批量移除事件
|
|
543
|
+
* @param name 事件名称
|
|
544
|
+
* @param target 事件目标
|
|
545
|
+
*/
|
|
546
|
+
static removeByNameAndTarget(name, target) {
|
|
547
|
+
this.event.removeByNameAndTarget(name, target);
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* 清空所有事件
|
|
551
|
+
*/
|
|
552
|
+
static clearAll() {
|
|
553
|
+
this.event.clearAll();
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
/**
|
|
557
|
+
* 事件管理器
|
|
558
|
+
* @internal
|
|
559
|
+
*/
|
|
560
|
+
GlobalEvent.event = new EventManager();
|
|
561
|
+
|
|
562
|
+
export { EventManager, GlobalEvent };
|