# 4.6 Performance

## 4.6 Performance

Mit der Kenntnis des Rendering-Prozesses einer Webseite lässt sich eine gute Performance umsetzen. Dieser Ablauf ist im Kapitel [**Hintergrund**](../2.-hintergrund) unter [**Rendering-Prozess**](../2.-hintergrund/2.4-browser-and-html-renderer) genau beschrieben. Die folgende Abbildung 4.14 zeigt die Kernelemente des Prozesses nochmals im Überblick.

<figure><img src="https://992617930-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F6gG3ZwRamlY91jTcyxr6%2Fuploads%2Fj66TLohxlgiAP7uCysi9%2Frendering-process.png?alt=media&#x26;token=2497b034-84b1-4550-8a69-f71aaaa5f40f" alt="" width="375"><figcaption><p>Abbildung 4.14: Rendering-Prozess</p></figcaption></figure>

Zur Auffrischung die wichtigsten Punkte nochmals: Der Browser kann die Webseite maximal 60 Mal pro Sekunde neu zeichnen. Änderungen am DOM und am CSSOM (Abbildung 4.14) lösen das Rendern aus.

Deswegen müssen viele kleine Änderungen ausserhalb des Browser-DOMs _<mark style="color:purple;">\[6]</mark>_ (Abbildung 4.14 rechts) – am besten in einem sogenannten Shadow-DOM – geschehen. Ein Shadow-DOM ist ein Teilbaum, welcher nicht am Browser-DOM angehängt ist. Für einen reibungslosen Ablauf ist es sinnvoll, die Änderungen nach dem Abhängen des Elternknotens zu vollziehen. Nach den Änderungen ist der Teilbaum wieder an den gewünschten Ort einzuhängen.

{% code title="Code 4.10: Performance-Optimierung" lineNumbers="true" %}
```javascript
const addAllOptions = (options) => {
    const placeHolder = createHolder();
    columnView.replaceWith(placeHolder);
    if (options.length > 50) {
        // same work as else but async
    } else {
        options.forEach((option) => {
            optionsController.addOption(option);
        });
        updateScrollbar(columnView);
        placeHolder.replaceWith(columnView);
    }
};
```
{% endcode %}

Code 4.10 ist eine Stelle, die diese Technik verwendet. Das Anzeigen eines Platzhalters mit einem Lade-Indikator an der Ursprungsstelle bewirkt, dass der Nutzer ein Feedback erhält. Sobald der Spalten-Container abgekoppelt ist, lädt die Funktion die Optionen in den Shadow-DOM. Nach Abschluss ersetzt sich der Lade-Indikator der originalen Stelle im Renderbaum durch den Container mit den neuen Elementen.

Weiterhin ist darauf zu achten, dass CSS-Klassen _<mark style="color:purple;">\[7]</mark>_ an Stelle von Inline-Styles _<mark style="color:purple;">\[8]</mark>_ ihre Verwendung finden. Die Selektoren sollten hierarchisch möglichst flach und nicht verschachtelt sein. Wenn es die Situation erlaubt, ist es besser, nicht mit `innerHTML` zu arbeiten. In diesem Projekt ist es für die Anzeige der Label jedoch nötig, `innerHTML` zu nutzen. Dies liegt daran, dass ein Label auch ein Bild enthalten kann. Generell verwendet die neue Auswahlkomponente keine Inline-Styles. Die einzige Ausnahme betrifft das verborgene Eingabefeld. Durch den Code 4.11 sind die Properties vor dem einfachen Überschreiben _<mark style="color:purple;">\[9]</mark>_ geschützt.

{% code title="Code 4.11: Inline-Style für Input-Feld" lineNumbers="true" %}
```javascript
inputElement.setAttribute(
    "style", "all:            unset       !important; " +
             "z-index:        -1          !important; " +
             "position:       absolute    !important; " +
             "inset:          5px         !important; " +
             "color:          transparent !important; " +
             "pointer-events: none        !important; "
);
```
{% endcode %}

Die Regeln in Code4.11 sorgen dafür, dass das Input-Feld sowohl transparent als auch resettet ist. Zudem befindet es sich im Hintergrund und besitzt dieselbe Grösse wie der Container mit dem ausgewählten Wert.



### 4.6.1 Performance-Vergleich

Durch die Anpassungen der Performance-Optimierung verschnellert sich die Ladezeit bei grossen Datenmengen enorm. Die Testseite enthält vier existierende und vier neue Auswahlkomponenten mit denselben Inhalten wie je eine der existierenden. Je eine der Selects enthält eine grosse Datenmenge von über 4'000 Werten. Die folgenden zwei Bilder 4.15 und 4.16 zeigen die Messung während des Seitenaufbaus.

<figure><img src="https://992617930-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F6gG3ZwRamlY91jTcyxr6%2Fuploads%2FbXqbHzvoo9KnfOdZzhqm%2Fperformance-before-user-tests-zoom.png?alt=media&#x26;token=41b0520c-e1ba-4fb0-bfc5-11064cc064ba" alt=""><figcaption><p>Abbildung 4.15: Performance-Test vor Anpassungen</p></figcaption></figure>

Die Grafik 4.15 zeigt die mit über 5 Sekunden (rechts unten in Blau) lange Ladedauer der früheren Version. Die Implementation führte sehr viele Aktionen auf dem Renderbaum aus. Die lange Wartezeit bestätigten mehrere Feedbacks der Nutzer – mehr dazu im Kapitel [**User-Tests**](../4.7-testing#id-4.7.3-user-tests).

<figure><img src="https://992617930-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F6gG3ZwRamlY91jTcyxr6%2Fuploads%2FLdnJ81GEXnAll9Rt9hA7%2Fperformance-after-user-tests-zoom.png?alt=media&#x26;token=af4d9f37-1b5d-4802-b626-cb95d16a2fc5" alt=""><figcaption><p>Abbildung 4.16: Performance-Test nach Anpassungen</p></figcaption></figure>

Ein Refactoring der früheren Implementation führt zur Auslagerung der aufwendigen Arbeiten auf den Shadow-DOM. Dadurch verkürzt sich der Ladevorgang um vier bis fünf Sekunden auf knapp 0.4 Sekunden (Abbildung 4.16 rechts unten in Blau). Der Vergleich zwischen Abbildung 4.15 und 4.16 zeigt, dass die Seite um Faktor 13 schneller lädt. Feedbacks zu den durchgeführten User-Tests mit Programmierern wie auch Endnutzern sowie manuelle Tests sind im nachfolgenden Kapitel aufgeführt.



_<mark style="color:purple;">\[6]</mark>_ Im Renderbaum verwendeter und im Browser angezeigter DOM\
&#xNAN;_<mark style="color:purple;">\[7]</mark>_ [(Ofoegbu, 2023)](../verzeichnisse/quellenverzeichnis) \
&#xNAN;_<mark style="color:purple;">\[8]</mark>_ Offizieller Begriff: Element attached style ⇒ Styles direkt im HTML-Element mit Attribut `style` definiert \
&#xNAN;_<mark style="color:purple;">\[9]</mark>_ `!important` nicht verwenden

