mirror of
https://gitee.com/antv/g6.git
synced 2024-12-02 03:38:20 +08:00
fix: fix issue that cause memory leak (#5587)
* fix: fix issue that may cause memories lack * test: adjust test case to destroy graph
This commit is contained in:
parent
72c5e74611
commit
bcd080432f
@ -9,6 +9,10 @@ describe('behavior combo expand collapse', () => {
|
||||
graph = await createDemoGraph(comboExpandCollapse, { animation: false });
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
graph.destroy();
|
||||
});
|
||||
|
||||
it('default status', async () => {
|
||||
await expect(graph).toMatchSnapshot(__filename);
|
||||
});
|
||||
|
@ -11,6 +11,10 @@ describe('behavior drag canvas', () => {
|
||||
graph = await createDemoGraph(behaviorDragCanvas, { animation: false });
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
graph.destroy();
|
||||
});
|
||||
|
||||
it('default status', () => {
|
||||
expect(graph.getBehaviors()).toEqual([
|
||||
'drag-canvas',
|
||||
@ -78,8 +82,4 @@ describe('behavior drag canvas', () => {
|
||||
|
||||
await expect(graph).toMatchSnapshot(__filename);
|
||||
});
|
||||
|
||||
it('destroy', () => {
|
||||
graph.destroy();
|
||||
});
|
||||
});
|
||||
|
@ -9,6 +9,10 @@ describe('behavior drag combo', () => {
|
||||
graph = await createDemoGraph(comboExpandCollapse, { animation: false });
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
graph.destroy();
|
||||
});
|
||||
|
||||
it('default status', async () => {
|
||||
graph.setBehaviors([{ type: 'drag-element', dropEffect: 'link' }]);
|
||||
graph.expand('combo-1');
|
||||
|
@ -10,6 +10,10 @@ describe('behavior drag element', () => {
|
||||
graph = await createDemoGraph(behaviorDragNode, { animation: false });
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
graph.destroy();
|
||||
});
|
||||
|
||||
it('default status', async () => {
|
||||
await expect(graph).toMatchSnapshot(__filename);
|
||||
|
||||
|
@ -11,6 +11,10 @@ describe('behavior zoom canvas', () => {
|
||||
graph = await createDemoGraph(behaviorZoomCanvas, { animation: false });
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
graph.destroy();
|
||||
});
|
||||
|
||||
it('default status', () => {
|
||||
expect(graph.getZoom()).toBe(1);
|
||||
expect(graph.getBehaviors()).toEqual([{ type: 'zoom-canvas' }]);
|
||||
@ -191,8 +195,4 @@ describe('behavior zoom canvas', () => {
|
||||
container?.dispatchEvent(new Event(ContainerEvent.KEY_DOWN));
|
||||
expect(keydownListener).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('destroy', () => {
|
||||
graph.destroy();
|
||||
});
|
||||
});
|
||||
|
@ -9,6 +9,10 @@ describe('element change type', () => {
|
||||
graph = await createDemoGraph(elementChangeType, { animation: false });
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
graph.destroy();
|
||||
});
|
||||
|
||||
it('default status', async () => {
|
||||
await expect(graph).toMatchSnapshot(__filename);
|
||||
});
|
||||
|
@ -9,6 +9,10 @@ describe('combo', () => {
|
||||
graph = await createDemoGraph(combo, { animation: false });
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
graph.destroy();
|
||||
});
|
||||
|
||||
it('default status', async () => {
|
||||
await expect(graph).toMatchSnapshot(__filename);
|
||||
});
|
||||
|
@ -26,6 +26,10 @@ describe('edge polyline', () => {
|
||||
graph = await createDemoGraph(edgePolyline, { animation: false });
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
graph.destroy();
|
||||
});
|
||||
|
||||
it('Control Points', async () => {
|
||||
updateEdgeStyle(graph, 'edge-1', 'controlPoints', [[300, 190]]);
|
||||
|
||||
|
@ -25,6 +25,10 @@ describe('element port', () => {
|
||||
graph = await createDemoGraph(elementPort, { animation: false });
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
graph.destroy();
|
||||
});
|
||||
|
||||
it('default status', async () => {
|
||||
await expect(graph).toMatchSnapshot(__filename, 'port_hidden');
|
||||
});
|
||||
|
@ -9,6 +9,10 @@ describe('element position combo', () => {
|
||||
graph = await createDemoGraph(elementPositionCombo, { animation: false });
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
graph.destroy();
|
||||
});
|
||||
|
||||
it('default status', async () => {
|
||||
await expect(graph).toMatchSnapshot(__filename);
|
||||
});
|
||||
|
@ -9,6 +9,10 @@ describe('element position', () => {
|
||||
graph = await createDemoGraph(elementPosition, { animation: false });
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
graph.destroy();
|
||||
});
|
||||
|
||||
it('default status', async () => {
|
||||
await expect(graph).toMatchSnapshot(__filename);
|
||||
});
|
||||
|
@ -9,6 +9,10 @@ describe('element state', () => {
|
||||
graph = await createDemoGraph(elementState, { animation: false });
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
graph.destroy();
|
||||
});
|
||||
|
||||
it('default status', async () => {
|
||||
await expect(graph).toMatchSnapshot(__filename);
|
||||
});
|
||||
|
@ -9,6 +9,10 @@ describe('element visibility', () => {
|
||||
graph = await createDemoGraph(elementVisibility, { animation: false });
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
graph.destroy();
|
||||
});
|
||||
|
||||
it('default status', async () => {
|
||||
await expect(graph).toMatchSnapshot(__filename);
|
||||
});
|
||||
|
@ -9,6 +9,10 @@ describe('element zIndex', () => {
|
||||
graph = await createDemoGraph(elementZIndex, { animation: false });
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
graph.destroy();
|
||||
});
|
||||
|
||||
it('default status', async () => {
|
||||
await expect(graph).toMatchSnapshot(__filename);
|
||||
});
|
||||
|
@ -14,6 +14,10 @@ describe('plugin grid line', () => {
|
||||
.getElementsByClassName('g6-grid-line')! as HTMLCollectionOf<HTMLElement>;
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
graph.destroy();
|
||||
});
|
||||
|
||||
it('default status', () => {
|
||||
expect(graph.getPlugins()).toEqual([{ type: 'grid-line', follow: false }]);
|
||||
expect(gridLineElement.length).toBe(1);
|
||||
|
@ -8,10 +8,15 @@ import { omit } from '@antv/util';
|
||||
|
||||
describe('ElementController', () => {
|
||||
let graph: Graph;
|
||||
|
||||
beforeAll(async () => {
|
||||
graph = await createDemoGraph(graphElement);
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
graph.destroy();
|
||||
});
|
||||
|
||||
it('static', async () => {
|
||||
await expect(graph).toMatchSnapshot(__filename);
|
||||
|
||||
|
@ -316,7 +316,7 @@ describe('Graph', () => {
|
||||
it('destroy', () => {
|
||||
graph.destroy();
|
||||
// @ts-expect-error context is private.
|
||||
expect(graph.context).toBeUndefined();
|
||||
expect(graph.context).toEqual({});
|
||||
expect(graph.destroyed).toBe(true);
|
||||
});
|
||||
});
|
||||
|
@ -6,10 +6,15 @@ import { AABB } from '@antv/g';
|
||||
|
||||
describe('ViewportController', () => {
|
||||
let graph: Graph;
|
||||
|
||||
beforeAll(async () => {
|
||||
graph = await createDemoGraph(controllerViewport);
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
graph.destroy();
|
||||
});
|
||||
|
||||
it('viewport center', () => {
|
||||
expect(graph.getViewportCenter()).toBeCloseTo([250, 250, 0]);
|
||||
});
|
||||
@ -104,18 +109,19 @@ describe('ViewportController', () => {
|
||||
// @ts-expect-error
|
||||
expect(graph.context.viewport.getBBoxInViewport(bbox).halfExtents).toBeCloseTo([100, 100, 0]);
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
graph.destroy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Viewport Fit without Animation', () => {
|
||||
let graph: Graph;
|
||||
|
||||
beforeAll(async () => {
|
||||
graph = await createDemoGraph(viewportFit);
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
graph.destroy();
|
||||
});
|
||||
|
||||
it('default', async () => {
|
||||
await expect(graph).toMatchSnapshot(__filename, 'before-fit');
|
||||
});
|
||||
@ -144,18 +150,19 @@ describe('Viewport Fit without Animation', () => {
|
||||
await graph.fitCenter();
|
||||
await expect(graph).toMatchSnapshot(__filename, 're-fitCenter');
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
graph.destroy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Viewport Fit with Animation', () => {
|
||||
let graph: Graph;
|
||||
|
||||
beforeAll(async () => {
|
||||
graph = await createDemoGraph(viewportFit, { animation: true });
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
graph.destroy();
|
||||
});
|
||||
|
||||
it('default', async () => {
|
||||
await expect(graph).toMatchSnapshot(__filename, 'before-fit-animation');
|
||||
});
|
||||
@ -184,10 +191,6 @@ describe('Viewport Fit with Animation', () => {
|
||||
await graph.fitCenter();
|
||||
await expect(graph).toMatchSnapshot(__filename, 're-fitCenter-animation');
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
graph.destroy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Viewport Fit with AutoFit and Padding without Animation', () => {
|
||||
@ -199,6 +202,10 @@ describe('Viewport Fit with AutoFit and Padding without Animation', () => {
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
graph.destroy();
|
||||
});
|
||||
|
||||
it('default', async () => {
|
||||
await expect(graph).toMatchSnapshot(__filename, 'auto-fit-with-padding');
|
||||
});
|
||||
@ -214,6 +221,10 @@ describe('Viewport Fit with AutoFit and Padding with Animation', () => {
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
graph.destroy();
|
||||
});
|
||||
|
||||
it('default', async () => {
|
||||
await expect(graph).toMatchSnapshot(__filename, 'auto-fit-with-padding-animation');
|
||||
});
|
||||
|
@ -9,6 +9,10 @@ describe('spec theme', () => {
|
||||
graph = await createDemoGraph(theme, { animation: false });
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
graph.destroy();
|
||||
});
|
||||
|
||||
it('theme', async () => {
|
||||
const theme: ThemeOptions = 'light';
|
||||
|
||||
|
@ -43,6 +43,7 @@
|
||||
"dev": "vite",
|
||||
"fix": "eslint ./src ./__tests__ --fix && prettier ./src __tests__ --write ",
|
||||
"jest": "node --expose-gc --max-old-space-size=4096 --unhandled-rejections=strict --experimental-vm-modules ../../node_modules/jest/bin/jest --coverage --logHeapUsage --detectOpenHandles",
|
||||
"jest:inspect": "node --inspect --expose-gc --max-old-space-size=4096 --unhandled-rejections=strict --experimental-vm-modules ../../node_modules/jest/bin/jest --coverage --logHeapUsage --detectOpenHandles --runInBand",
|
||||
"lint": "eslint ./src __tests__ --quiet && prettier ./src __tests__ --check",
|
||||
"prepublishOnly": "npm run ci",
|
||||
"size": "limit-size",
|
||||
|
@ -148,4 +148,10 @@ export abstract class BaseShape<StyleProps extends BaseShapeStyleProps> extends
|
||||
const { visibility } = this.attributes;
|
||||
setVisibility(this, visibility);
|
||||
}
|
||||
|
||||
public destroy(): void {
|
||||
this.shapeMap = {};
|
||||
this.animateMap = {};
|
||||
super.destroy();
|
||||
}
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ export class Tooltip extends BasePlugin<TooltipOptions> {
|
||||
}
|
||||
|
||||
public update(options: Partial<TooltipOptions>) {
|
||||
this.unbundEvents();
|
||||
this.unbindEvents();
|
||||
super.update(options);
|
||||
if (this.tooltipElement) {
|
||||
this.container?.removeChild(this.tooltipElement.HTMLTooltipElement);
|
||||
@ -83,7 +83,7 @@ export class Tooltip extends BasePlugin<TooltipOptions> {
|
||||
this.tooltipElement = this.initTooltip();
|
||||
}
|
||||
|
||||
private unbundEvents() {
|
||||
private unbindEvents() {
|
||||
const { graph } = this.context;
|
||||
/** The previous event binding needs to be removed when updating the trigger. */
|
||||
const events = this.getEvents();
|
||||
@ -259,7 +259,7 @@ export class Tooltip extends BasePlugin<TooltipOptions> {
|
||||
};
|
||||
|
||||
public destroy(): void {
|
||||
this.unbundEvents();
|
||||
this.unbindEvents();
|
||||
if (this.tooltipElement) {
|
||||
this.container?.removeChild(this.tooltipElement.HTMLTooltipElement);
|
||||
}
|
||||
|
@ -72,11 +72,9 @@ export abstract class ExtensionController<Extension extends BaseExtension<Loosel
|
||||
public destroy() {
|
||||
Object.values(this.extensionMap).forEach((extension) => extension.destroy());
|
||||
// @ts-expect-error force delete
|
||||
delete this.context;
|
||||
// @ts-expect-error force delete
|
||||
delete this.extensions;
|
||||
// @ts-expect-error force delete
|
||||
delete this.extensionMap;
|
||||
this.context = {};
|
||||
this.extensions = [];
|
||||
this.extensionMap = {};
|
||||
}
|
||||
}
|
||||
|
||||
@ -105,9 +103,9 @@ export class BaseExtension<T extends LooselyExtensionOption> {
|
||||
|
||||
public destroy() {
|
||||
// @ts-expect-error force delete
|
||||
delete this.context;
|
||||
this.context = {};
|
||||
// @ts-expect-error force delete
|
||||
delete this.options;
|
||||
this.options = {};
|
||||
|
||||
this.destroyed = true;
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ export class BehaviorController extends ExtensionController<BaseBehavior<CustomB
|
||||
const container = this.context.canvas.getContainer();
|
||||
if (container) {
|
||||
[ContainerEvent.KEY_DOWN, ContainerEvent.KEY_UP].forEach((name) => {
|
||||
container.addEventListener(name, this.forwardContainerEvents.bind(this));
|
||||
container.addEventListener(name, this.forwardContainerEvents);
|
||||
});
|
||||
}
|
||||
|
||||
@ -105,7 +105,18 @@ export class BehaviorController extends ExtensionController<BaseBehavior<CustomB
|
||||
}
|
||||
};
|
||||
|
||||
private forwardContainerEvents(event: FocusEvent | KeyboardEvent) {
|
||||
private forwardContainerEvents = (event: FocusEvent | KeyboardEvent) => {
|
||||
this.context.graph.emit(event.type, event);
|
||||
};
|
||||
|
||||
public destroy(): void {
|
||||
const container = this.context.canvas.getContainer();
|
||||
if (container) {
|
||||
[ContainerEvent.KEY_DOWN, ContainerEvent.KEY_UP].forEach((name) => {
|
||||
container.removeEventListener(name, this.forwardContainerEvents);
|
||||
});
|
||||
}
|
||||
this.context.canvas.document.removeAllEventListeners();
|
||||
super.destroy();
|
||||
}
|
||||
}
|
||||
|
@ -253,7 +253,10 @@ export class Canvas {
|
||||
}
|
||||
|
||||
public destroy() {
|
||||
Object.values(this.canvas).forEach((canvas) => {
|
||||
this.config = {};
|
||||
// @ts-expect-error force delete
|
||||
this.renderers = {};
|
||||
Object.entries(this.canvas).forEach(([name, canvas]) => {
|
||||
const camera = canvas.getCamera();
|
||||
// @ts-expect-error landmark is private
|
||||
if (camera.landmarks?.length) {
|
||||
@ -261,6 +264,8 @@ export class Canvas {
|
||||
}
|
||||
|
||||
canvas.destroy();
|
||||
// @ts-expect-error force delete
|
||||
this[name] = undefined;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -759,7 +759,7 @@ export class DataController {
|
||||
model.removeNodes(nodes.map((node) => node.id));
|
||||
|
||||
// @ts-expect-error force delete
|
||||
delete this.context;
|
||||
this.context = {};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -718,14 +718,19 @@ export class ElementController {
|
||||
}
|
||||
|
||||
public destroy() {
|
||||
Object.values(this.elementMap).forEach((element) => element.destroy());
|
||||
Object.values(this.container).forEach((container) => container.destroy());
|
||||
// @ts-expect-error force delete
|
||||
this.container = {};
|
||||
this.elementMap = {};
|
||||
this.shapeTypeMap = {};
|
||||
this.defaultStyle = {};
|
||||
this.stateStyle = {};
|
||||
this.paletteStyle = {};
|
||||
// @ts-expect-error force delete
|
||||
delete this.context;
|
||||
this.context = {};
|
||||
// @ts-expect-error force delete
|
||||
this.latestElementVisibilityMap = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -503,16 +503,17 @@ export class Graph extends EventEmitter {
|
||||
|
||||
public destroy(): void {
|
||||
const { layout, element, model, canvas, behavior, plugin } = this.context;
|
||||
plugin?.destroy();
|
||||
behavior?.destroy();
|
||||
layout?.destroy();
|
||||
element?.destroy();
|
||||
model.destroy();
|
||||
canvas?.destroy();
|
||||
behavior?.destroy();
|
||||
plugin?.destroy();
|
||||
this.options = {};
|
||||
// @ts-expect-error force delete
|
||||
delete this.context;
|
||||
this.context = {};
|
||||
|
||||
this.off();
|
||||
window.removeEventListener('resize', this.onResize);
|
||||
|
||||
this.destroyed = true;
|
||||
|
@ -381,7 +381,11 @@ export class LayoutController {
|
||||
public destroy() {
|
||||
this.stopLayout();
|
||||
// @ts-expect-error force delete
|
||||
delete this.context;
|
||||
this.context = {};
|
||||
this.supervisor?.kill();
|
||||
this.supervisor = undefined;
|
||||
this.instance = undefined;
|
||||
this.animationResult = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user