mirror of
https://github.com/Tencent/tmagic-editor.git
synced 2026-11-01 07:20:39 +00:00
fix(core): 节点销毁时移除其事件监听
迭代容器等场景会反复重建节点,此前 destroy 只清理事件队列, 事件监听仍留在 EventHelper 上导致泄漏。新增 removeNodeEventsOf, 在 Node.destroy 时按节点移除已绑定的监听
This commit is contained in:
parent
2f8a504163
commit
522a0068f5
@ -55,6 +55,7 @@ export default class EventHelper extends EventEmitter {
|
||||
public eventQueue: EventCache[] = [];
|
||||
|
||||
private nodeEventList = new Map<(fromCpt: TMagicNode, ...args: any[]) => void, symbol>();
|
||||
private nodeEventHandlers = new WeakMap<TMagicNode, ((fromCpt: TMagicNode, ...args: any[]) => void)[]>();
|
||||
private dataSourceEventList = new Map<string, Map<string, (...args: any[]) => void>>();
|
||||
private beforeEventHandler?: BeforeEventHandler;
|
||||
private afterEventHandler?: AfterEventHandler;
|
||||
@ -125,6 +126,13 @@ export default class EventHelper extends EventEmitter {
|
||||
|
||||
this.nodeEventList.set(eventHandler, eventName);
|
||||
this.on(eventName, eventHandler);
|
||||
|
||||
const handlers = this.nodeEventHandlers.get(node);
|
||||
if (handlers) {
|
||||
handlers.push(eventHandler);
|
||||
} else {
|
||||
this.nodeEventHandlers.set(node, [eventHandler]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -135,6 +143,25 @@ export default class EventHelper extends EventEmitter {
|
||||
}
|
||||
|
||||
this.nodeEventList.clear();
|
||||
this.nodeEventHandlers = new WeakMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除单个节点绑定的事件,节点销毁时调用,避免迭代容器等场景反复重建节点导致监听泄漏
|
||||
*/
|
||||
public removeNodeEventsOf(node: TMagicNode) {
|
||||
const handlers = this.nodeEventHandlers.get(node);
|
||||
if (!handlers) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const handler of handlers) {
|
||||
const name = this.nodeEventList.get(handler);
|
||||
name && this.off(name, handler);
|
||||
this.nodeEventList.delete(handler);
|
||||
}
|
||||
|
||||
this.nodeEventHandlers.delete(node);
|
||||
}
|
||||
|
||||
public bindDataSourceEvents() {
|
||||
|
||||
@ -149,6 +149,7 @@ class Node extends EventEmitter {
|
||||
}
|
||||
|
||||
public destroy() {
|
||||
this.app?.eventHelper?.removeNodeEventsOf(this);
|
||||
this.eventQueue.length = 0;
|
||||
this.instance = null;
|
||||
this.events = [];
|
||||
|
||||
@ -187,6 +187,67 @@ describe('EventHelper - bindNodeEvents / initEvents / removeNodeEvents', () => {
|
||||
helper.removeNodeEvents();
|
||||
expect((helper as any).nodeEventList.size).toBe(0);
|
||||
});
|
||||
|
||||
test('removeNodeEventsOf 只移除指定节点的监听,未绑定过的节点安全返回', () => {
|
||||
const app = new App({
|
||||
config: createDsl({
|
||||
items: [
|
||||
{
|
||||
type: NodeType.PAGE,
|
||||
id: 'page_1',
|
||||
items: [
|
||||
{ id: 'btn_1', type: 'button', events: [{ name: 'click', actions: [] }] },
|
||||
{ id: 'btn_2', type: 'button', events: [{ name: 'click', actions: [] }] },
|
||||
{ id: 'btn_3', type: 'button' },
|
||||
],
|
||||
},
|
||||
],
|
||||
} as any),
|
||||
});
|
||||
|
||||
const helper = app.eventHelper!;
|
||||
const node1 = app.getNode('btn_1')!;
|
||||
const node2 = app.getNode('btn_2')!;
|
||||
const symbol1 = node1.eventKeys.get('click_btn_1')!;
|
||||
const symbol2 = node2.eventKeys.get('click_btn_2')!;
|
||||
expect((helper as any).nodeEventList.size).toBe(2);
|
||||
|
||||
expect(() => helper.removeNodeEventsOf(app.getNode('btn_3')!)).not.toThrow();
|
||||
expect((helper as any).nodeEventList.size).toBe(2);
|
||||
|
||||
helper.removeNodeEventsOf(node1);
|
||||
expect((helper as any).nodeEventList.size).toBe(1);
|
||||
expect(helper.listenerCount(symbol1)).toBe(0);
|
||||
expect(helper.listenerCount(symbol2)).toBe(1);
|
||||
|
||||
// 重复调用无副作用
|
||||
helper.removeNodeEventsOf(node1);
|
||||
expect((helper as any).nodeEventList.size).toBe(1);
|
||||
});
|
||||
|
||||
test('节点 destroy 时会移除其在 eventHelper 上的监听', () => {
|
||||
const app = new App({
|
||||
config: createDsl({
|
||||
items: [
|
||||
{
|
||||
type: NodeType.PAGE,
|
||||
id: 'page_1',
|
||||
items: [{ id: 'btn_1', type: 'button', events: [{ name: 'click', actions: [] }] }],
|
||||
},
|
||||
],
|
||||
} as any),
|
||||
});
|
||||
|
||||
const helper = app.eventHelper!;
|
||||
const node = app.getNode('btn_1')!;
|
||||
const symbol = node.eventKeys.get('click_btn_1')!;
|
||||
expect(helper.listenerCount(symbol)).toBe(1);
|
||||
|
||||
node.destroy();
|
||||
|
||||
expect(helper.listenerCount(symbol)).toBe(0);
|
||||
expect((helper as any).nodeEventList.size).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('EventHelper - 事件队列', () => {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user