Ver Fonte

added caching of intermediates during svg parsing in LabIcon.element

- speeds up the javascript calls of LabIcon.element by 10x-20x

- the browser rendering calls take the same time, so overall this is a 2x-3x speedup
telamonian há 5 anos atrás
pai
commit
cd465c8436

+ 29 - 7
packages/ui-components/src/icon/labicon.tsx

@@ -327,25 +327,22 @@ export class LabIcon implements LabIcon.ILabIcon, VirtualElement.IRenderer {
     }
 
     // ensure that svg html is valid
-    const svgElement = this._initSvg({ uuid: this._uuid });
-    if (!svgElement) {
+    if (!this.svgElement) {
       // bail if failing silently, return blank element
       return document.createElement('div');
     }
 
-    let ret: HTMLElement;
+    let returnSvgElement = true;
     if (container) {
       // take ownership by removing any existing children
       while (container.firstChild) {
         container.firstChild.remove();
       }
-
-      ret = svgElement;
     } else {
       // create a container if needed
       container = document.createElement(tag);
 
-      ret = container;
+      returnSvgElement = false;
     }
     if (label != null) {
       container.textContent = label;
@@ -353,9 +350,10 @@ export class LabIcon implements LabIcon.ILabIcon, VirtualElement.IRenderer {
     Private.initContainer({ container, className, styleProps, title });
 
     // add the svg node to the container
+    let svgElement = this.svgElement.cloneNode(true) as HTMLElement;
     container.appendChild(svgElement);
 
-    return ret;
+    return returnSvgElement ? svgElement : container;
   }
 
   render(container: HTMLElement, options?: LabIcon.IRendererOptions): void {
@@ -372,6 +370,22 @@ export class LabIcon implements LabIcon.ILabIcon, VirtualElement.IRenderer {
     });
   }
 
+  get svgElement() {
+    if (this._svgElement === null) {
+      this._svgElement = this._initSvg({ uuid: this._uuid });
+    }
+
+    return this._svgElement;
+  }
+
+  get svgReactAttrs() {
+    if (this._svgReactAttrs === null && this._svgElement !== null) {
+      getReactAttrs(this._svgElement, { ignore: ['data-icon-id'] });
+    }
+
+    return this._svgReactAttrs;
+  }
+
   get svgstr() {
     return this._svgstr;
   }
@@ -394,6 +408,10 @@ export class LabIcon implements LabIcon.ILabIcon, VirtualElement.IRenderer {
         }
       });
 
+    // reset asset caches
+    this._svgElement = null;
+    this._svgReactAttrs = null;
+
     // trigger update of icon elements created using other methods
     this._svgReplaced.emit();
   }
@@ -564,6 +582,10 @@ export class LabIcon implements LabIcon.ILabIcon, VirtualElement.IRenderer {
   protected _svgReplaced = new Signal<this, void>(this);
   protected _svgstr: string;
   protected _uuid: string;
+
+  // cache vars
+  protected _svgElement: HTMLElement | null = null;
+  protected _svgReactAttrs: any | null = null;
 }
 
 /**

+ 7 - 2
packages/ui-components/src/utils.ts

@@ -66,12 +66,17 @@ export function classesDedupe(
  *
  * @param elem - A DOM element
  *
+ * @param ignore - An optional list of attribute names to ignore
+ *
  * @returns An object with key:value pairs that are the React-friendly
  * translation of elem's attributes
  */
-export function getReactAttrs(elem: Element) {
+export function getReactAttrs(
+  elem: Element,
+  { ignore = [] }: { ignore?: string[] } = {}
+) {
   return elem.getAttributeNames().reduce((d, name) => {
-    if (name === 'style') {
+    if (name === 'style' || ignore.includes(name)) {
       void 0;
     } else if (name.startsWith('data')) {
       d[name] = elem.getAttribute(name);