perf(editor): Improve canvas rendering performance (#8022)
## Summary - Refactor usage of `setSuspendDrawing`, removing it from loops and only calling it after batch operations are done - Batch adding of nodes to improve copy/paste and workflow load performance - Cache i18n calls - Debounce connections dragging handler if there are more than 20 nodes ## Related tickets and issues > Include links to **Linear ticket** or Github issue or Community forum post. Important in order to close *automatically* and provide context to reviewers. - https://community.n8n.io/t/slow-ui-in-big-scenarios/33830/8 --------- Signed-off-by: Oleg Ivaniv <me@olegivaniv.com>
This commit is contained in:
@@ -23,6 +23,8 @@ export const i18nInstance = createI18n({
|
||||
});
|
||||
|
||||
export class I18nClass {
|
||||
private baseTextCache = new Map<string, string>();
|
||||
|
||||
private get i18n() {
|
||||
return i18nInstance.global;
|
||||
}
|
||||
@@ -50,11 +52,25 @@ export class I18nClass {
|
||||
key: BaseTextKey,
|
||||
options?: { adjustToNumber?: number; interpolate?: { [key: string]: string } },
|
||||
): string {
|
||||
if (options?.adjustToNumber !== undefined) {
|
||||
return this.i18n.tc(key, options.adjustToNumber, options?.interpolate).toString();
|
||||
// Create a unique cache key
|
||||
const cacheKey = `${key}-${JSON.stringify(options)}`;
|
||||
|
||||
// Check if the result is already cached
|
||||
if (this.baseTextCache.has(cacheKey)) {
|
||||
return this.baseTextCache.get(cacheKey) ?? key;
|
||||
}
|
||||
|
||||
return this.i18n.t(key, options?.interpolate).toString();
|
||||
let result: string;
|
||||
if (options?.adjustToNumber !== undefined) {
|
||||
result = this.i18n.tc(key, options.adjustToNumber, options?.interpolate ?? {}).toString();
|
||||
} else {
|
||||
result = this.i18n.t(key, options?.interpolate ?? {}).toString();
|
||||
}
|
||||
|
||||
// Store the result in the cache
|
||||
this.baseTextCache.set(cacheKey, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -70,7 +70,6 @@ export const register = () => {
|
||||
container.appendChild(unconnectedGroup);
|
||||
container.appendChild(defaultGroup);
|
||||
|
||||
endpointInstance.setupOverlays();
|
||||
endpointInstance.setVisible(false);
|
||||
|
||||
return container;
|
||||
|
||||
@@ -33,11 +33,6 @@ export class N8nAddInputEndpoint extends EndpointRepresentation<ComputedN8nAddIn
|
||||
|
||||
type = N8nAddInputEndpoint.type;
|
||||
|
||||
setupOverlays() {
|
||||
this.endpoint.instance.setSuspendDrawing(true);
|
||||
this.endpoint.instance.setSuspendDrawing(false);
|
||||
}
|
||||
|
||||
bindEvents() {
|
||||
this.instance.bind(EVENT_ENDPOINT_CLICK, this.fireClickEvent);
|
||||
}
|
||||
|
||||
@@ -49,7 +49,6 @@ export class N8nPlusEndpoint extends EndpointRepresentation<ComputedN8nPlusEndpo
|
||||
|
||||
setupOverlays() {
|
||||
this.clearOverlays();
|
||||
this.endpoint.instance.setSuspendDrawing(true);
|
||||
this.stalkOverlay = this.endpoint.addOverlay({
|
||||
type: 'Custom',
|
||||
options: {
|
||||
@@ -78,7 +77,6 @@ export class N8nPlusEndpoint extends EndpointRepresentation<ComputedN8nPlusEndpo
|
||||
},
|
||||
},
|
||||
});
|
||||
this.endpoint.instance.setSuspendDrawing(false);
|
||||
}
|
||||
|
||||
bindEvents() {
|
||||
@@ -151,18 +149,14 @@ export class N8nPlusEndpoint extends EndpointRepresentation<ComputedN8nPlusEndpo
|
||||
}
|
||||
|
||||
setIsVisible(visible: boolean) {
|
||||
this.instance.setSuspendDrawing(true);
|
||||
Object.keys(this.endpoint.getOverlays()).forEach((overlay) => {
|
||||
this.endpoint.getOverlays()[overlay].setVisible(visible);
|
||||
});
|
||||
|
||||
this.setVisible(visible);
|
||||
|
||||
// Re-trigger the success state if label is set
|
||||
if (visible && this.label) {
|
||||
this.setSuccessOutput(this.label);
|
||||
}
|
||||
this.instance.setSuspendDrawing(false);
|
||||
}
|
||||
|
||||
setSuccessOutput(label: string) {
|
||||
|
||||
Reference in New Issue
Block a user