Startseite / Artikel

Virtual DOM-Diffing entmystifiziert: Was React vergleicht und warum das vorteilhaft ist

Verstehen Sie, was Reacts Virtueller DOM wirklich ist, wie Reconciliation zwei Elementbäume vergleicht, welche Änderungen in der Commit-Phase stattfinden und woher der Leistungsvorteil stammt.

Verlag: REACTAPP.TOP4 Min. Lesezeit1032 Wörter

Quellen: How React Virtual DOM Works Under the Hood

Die Schnittstellen ändern sich ständig: Es erscheint eine Benachrichtigung, ein Button wechselt den Zustand, ein Zähler erhöht sich, eine Liste wird neu gerendert. Jede solche Änderung muss im Browser-DOM ankommen, und eine unvorsichtige Aktualisierung des DOMs ist ein zuverlässiger Weg, damit eine Seite langsam wirkt. Reacts Lösung besteht aus dem Virtual DOM sowie einem Vergleichsschritt namens Reconciliation. Dieser Artikel erklärt, was React im Speicher behält, wie es feststellt, was sich geändert hat, und warum das hilft, damit Sie Updates mit einem präzisen mentalen Modell verstehen können.

Warum das Direkt-Schreiben ins DOM teuer wird

Vor React waren UI-Updates imperativ: Man suchte einen Knoten und änderte ihn.

document.getElementById("title").innerText = "Hello";

Das funktioniert bei einer kleinen Seite noch. Wenn Hunderte oder Tausende von Elementen häufig geändert werden, wird es sowohl langsam als auch schwierig zu verwalten, denn eine Änderung im DOM kann den Browser dazu zwingen, Folgendes erneut durchzuführen:

  • Berechnung von Stil und Layout
  • Aufrüsten des umliegenden Inhalts
  • Aufrisszeichnen der betroffenen Pixel
  • Neuerender von Teilen der Seite
  • Jedes Mal berechnet der Browser erneut, wo die Elemente liegen, wie groß sie sind und welche Pixel neu gezeichnet werden müssen. Diese Arbeit ist weitaus aufwendiger als die Erstellung oder Vergleich von JavaScript-Objekten. Hinzu kommt, dass viele Codeabschnitte unabhängig auf den DOM zugreifen, was dazu führt, dass der Bildschirm leicht aus dem Einklang mit dem Zustand der Anwendung gerät.

    Was der Virtuelle DOM tatsächlich ist

    Der echte DOM

    Der echte DOM ist der lebende Knotenbaum, den der Browser aus dem Markup erstellt – ein Knoten pro Element. Selbst das hier:

    <body>
      <h1>Hello</h1>
    </body>
    

    werden zu einem internen Baum, der mit dem Layout und dem Zeichnen verbunden ist, und seine häufige Änderung löst die oben beschriebene aufwändige Arbeit aus.

    Die virtuelle Repräsentation

    Der Virtuelle DOM wird oft als leichtgewichtige Kopie des echten DOM bezeichnet. Genauer gesagt handelt es sich dabei um eine Beschreibung davon, wie die Benutzeroberfläche aussehen sollte: einfache Objekte, die von den Komponenten bei der Darstellung zurückgegeben werden. React aktualisiert zunächst diese Beschreibung und greift anschließend auf den Browser zu. Ein Element sieht in etwa so aus:

    {
      type: "h1",
      props: {
        children: "Hello"
      }
    }
    

    Solche Objekte sind günstig in der Erstellung und im Vergleich, sodass React herausfinden kann, was sich geändert hat, bevor irgendwelche tatsächlichen DOM-Operationen durchgeführt werden. JSX ist lediglich eine Syntax zur Erzeugung dieser Objekte.

    Von der ersten Darstellung bis zu einem geänderten Baum

    Bei der ersten Darstellung einer solchen Komponente:

    function App() {
      return <h1>Hello World</h1>;
    }
    

    React erstellt den virtuellen Baum, erzeugt entsprechende DOM-Node und fügt sie in die Seite ein. Die beiden Bäume stimmen nun überein, und die Benutzeroberfläche ist sichtbar.

    Später könnte ein Klick-Handler den Zustand aktualisieren:

    setCount(count + 1);
    

    oder ein Elternteil übermittelt neue Eigenschaften. Das signalisiert, dass sich ein Teil der Benutzeroberfläche ändern könnte. React patcht den DOM nicht sofort; es plant eine neue Darstellung und aktualisiert die Ergebnisse desselben Ereignisses in der Regel zusammen.

    Während dieser Darstellung ruft React das Komponentenobjekt erneut auf und erhält einen neuen Baum, sodass nun sowohl die vorherige als auch die neue Version vorhanden sind. Der alte Baum:

    <h1>Hello</h1>
    

    Der neue Baum:

    <h1>Hello Omer</h1>
    

    Die Aufgabe besteht darin, genau herauszufinden, was sich unterscheidet.

    Ausgleich: Wie der Diff funktioniert

    Ausgleich bedeutet, den vorherigen virtuellen Baum mit dem neuen zu vergleichen; dieser Vergleich selbst wird in der Regel als Diffing bezeichnet. Für jede Position fragt React nach, ob sich ein Element geändert hat, unverändert blieb oder hinzugefügt bzw. entfernt wurde. Konzeptionell:

    Old Tree  VS  New Tree
    

    Ziel ist die kleinste mögliche Anzahl an Änderungen, um das alte UI in ein neues zu verwandeln. Ein vollständig allgemeiner Baum-Vergleich wäre zu langsam, weshalb React zwei Heuristiken verwendet. Wenn sich der Typ eines Elements ändert – beispielsweise von div zu span – ersetzt React diesen Unterbaum anstelle der Kinder dieses Elements. In Listen werden die Kinder über den key abgeglichen, weshalb stabile Schlüssel wichtig sind: Sie signalisieren React, dass ein Element verschoben wurde und nicht ersetzt.

    Wenn sich nur der Text ändert

    Vorher:

    <h1>Hello</h1>
    

    Nachher:

    <h1>Hello Omer</h1>
    

    Der <h1>-Element hat am selben Ort denselben Typ; nur sein Text unterscheidet sich. React behält daher den vorhandenen DOM-Node bei und aktualisiert nur den Text-Node, anstatt das Element neu zu erstellen. Das Auslassen jeder nicht unbedingt notwendigen Operation ist der Kern der Optimierung.

    Die Commit-Phase: Nur die veränderten Teile werden angewendet

    Nach dem Vergleich schreibt React die resultierenden Änderungen in den echten DOM:

    • Aktualisierung von Texten
    • Einstellen oder Entfernen von Attributen
    • Einfügen neuer Elemente
    • Löschen von Elementen, die verschwunden sind

    Das ist die Commit-Phase – der einzige Punkt, an dem React den DOM berührt – und sie ändert nur das, was durch den Vergleich markiert wurde. Der Browser malt anschließend die betroffenen Bereiche neu aus. Für eine detailliertere Erklärung zum Weg vom Commit bis zu den Pixeln siehe unsere Anleitung zur Darstellung in React von Zustandsänderungen zu Bildschirmpixeln.

    Woher der Leistungsvorteil stammt

    Der Vorteil ergibt sich aus weniger teuren DOM-Operationen. Anstatt alles neu zu erstellen, vergleicht React die alten und neuen Beschreibungen, berechnet die minimalen Unterschiede und betrifft nur die betroffenen Knoten. Da der Vergleich von Objekten viel günstiger ist als eine DOM-Änderung, lohnt sich dies in der Regel in großen Anwendungen.

    Zwei Einschränkungen sorgen dafür, dass das Modell realistisch bleibt. Der Virtuelle DOM ist nicht von Natur aus schneller als sorgfältig angepasster DOM-Code; sein Wert liegt darin, dass er es ermöglicht, deklarative Benutzeroberflächen zu schreiben und dennoch effiziente Aktualisierungen zu erzielen. Zudem ist das Rendering nicht kostenlos: React ruft weiterhin Ihre Komponenten auf und vergleicht deren Ausgabe, weshalb unnotwendige erneute Renderungen zu vermeiden weiterhin wichtig ist.

    Kernpunkte

    • Der Virtuelle DOM ist eine Sammlung einfacher Objekte, die die gewünschte Benutzeroberfläche beschreiben und bei jedem Render neu erstellt werden.
  • Abgleich der Unterschiede zwischen altem und neuem Baum unter Verwendung des Elementtyps sowie von key als Abkürzungen.
  • Die Commit-Phase ist der einzige Ort, an dem React in den DOM schreibt, und dabei werden nur die Unterschiede gespeichert.
  • Man tauscht etwas Render- und Abgleichsaufwand gegen deutlich weniger aufwändige DOM-Änderungen sowie ein einfacheres Programmiermodell ein.
  • Verwandte Artikel