Articles

bitsofcode

Ich habe kürzlich darüber geschrieben, was genau das DOM und das Schatten-DOM sind und wie sie sich unterscheiden. Zur Erinnerung: Das Document Object Model ist eine objektbasierte Darstellung eines HTML-Dokuments und eine Schnittstelle zur Bearbeitung dieses Objekts. Das Shadow-DOM kann als eine „Lite“-Version des DOM betrachtet werden. Es handelt sich ebenfalls um eine objektbasierte Darstellung von HTML-Elementen, aber nicht um ein vollständiges, eigenständiges Dokument. Stattdessen erlaubt uns das Shadow-DOM, unser DOM in kleinere, gekapselte Teile aufzuteilen, die in allen HTML-Dokumenten verwendet werden können.

Ein weiterer ähnlicher Begriff, der Ihnen vielleicht schon begegnet ist, ist das „virtuelle DOM“. Obwohl es dieses Konzept schon seit einigen Jahren gibt, wurde es durch seine Verwendung im React-Framework populärer gemacht. In diesem Artikel werde ich genau erklären, was das virtuelle DOM ist, wie es sich vom ursprünglichen DOM unterscheidet und wie es verwendet wird.

Warum brauchen wir ein virtuelles DOM?

Um zu verstehen, warum das Konzept des virtuellen DOMs entstanden ist, lassen Sie uns das ursprüngliche DOM noch einmal betrachten. Wie ich bereits erwähnt habe, besteht das DOM aus zwei Teilen – der objektbasierten Darstellung des HTML-Dokuments und der API zur Manipulation dieses Objekts.

Nehmen wir zum Beispiel dieses einfache HTML-Dokument mit einer ungeordneten Liste und einem Listenelement.

<!doctype html><html lang="en"> <head></head> <body> <ul class="list"> <li class="list__item">List item</li> </ul> </body></html>

Dieses Dokument kann als der folgende DOM-Baum dargestellt werden:

  • html
    • head lang=“en“
    • body
      • ul class=“list“
        • li class=“list__item“
          • „Listenelement“

Angenommen, wir wollen den Inhalt des ersten Listenelements in "List item one" ändern und ein zweites Listenelement hinzufügen. Dazu müssen wir die DOM-APIs verwenden, um die zu aktualisierenden Elemente zu finden, die neuen Elemente zu erstellen, Attribute und Inhalte hinzuzufügen und schließlich die DOM-Elemente selbst zu aktualisieren.

const listItemOne = document.getElementsByClassName("list__item");listItemOne.textContent = "List item one";const list = document.getElementsByClassName("list");const listItemTwo = document.createElement("li");listItemTwo.classList.add("list__item");listItemTwo.textContent = "List item two";list.appendChild(listItemTwo);

Das DOM war dafür nicht gedacht…

Als die erste Spezifikation für das DOM 1998 veröffentlicht wurde, haben wir Webseiten auf ganz andere Weise erstellt und verwaltet. Es gab weit weniger Vertrauen in die DOM-APIs, um den Seiteninhalt so häufig zu erstellen und zu aktualisieren, wie wir es heute tun.

Einfache Methoden wie document.getElementsByClassName() sind in kleinem Rahmen gut zu gebrauchen, aber wenn wir mehrere Elemente auf einer Seite alle paar Sekunden aktualisieren, kann es anfangen, wirklich teuer zu werden, das DOM ständig abzufragen und zu aktualisieren.

Weiterhin ist es aufgrund der Art und Weise, wie die APIs aufgebaut sind, in der Regel einfacher, teurere Operationen durchzuführen, bei denen wir größere Teile des Dokuments aktualisieren, als die spezifischen Elemente zu finden und zu aktualisieren. Um auf unser Listenbeispiel zurückzukommen, ist es in gewisser Weise einfacher, die gesamte ungeordnete Liste durch eine neue zu ersetzen, als die einzelnen Elemente zu ändern.

const list = document.getElementsByClassName("list");list.innerHTML = `<li class="list__item">List item one</li><li class="list__item">List item two</li>`;

In diesem speziellen Beispiel ist der Leistungsunterschied zwischen den Methoden wahrscheinlich unbedeutend. Mit zunehmender Größe der Webseite wird es jedoch immer wichtiger, nur das auszuwählen und zu aktualisieren, was benötigt wird.

… aber das virtuelle DOM!

Das virtuelle DOM wurde geschaffen, um diese Probleme der häufigen Aktualisierung des DOM auf eine leistungsfähigere Weise zu lösen. Anders als das DOM oder das Shadow-DOM ist das virtuelle DOM keine offizielle Spezifikation, sondern eher eine neue Methode, mit dem DOM zu interagieren.

Ein virtuelles DOM kann man sich als eine Kopie des ursprünglichen DOM vorstellen. Diese Kopie kann häufig manipuliert und aktualisiert werden, ohne die DOM-APIs zu verwenden. Sobald alle Aktualisierungen am virtuellen DOM vorgenommen wurden, können wir uns ansehen, welche spezifischen Änderungen am ursprünglichen DOM vorgenommen werden müssen, und diese zielgerichtet und optimiert durchführen.

Wie sieht ein virtuelles DOM aus?

Der Name „virtuelles DOM“ trägt dazu bei, das Konzept zu verschleiern. Tatsächlich ist ein virtuelles DOM nur ein normales Javascript-Objekt.

Lassen Sie uns noch einmal den DOM-Baum betrachten, den wir vorhin erstellt haben:

  • html
    • head lang=“en“
    • body
      • ul class=“list“
        • li class=“list__item“
          • „Listenelement“

Dieser Baum kann auch als Javascript-Objekt dargestellt werden.

const vdom = { tagName: "html", children: } // end ul ] } // end body ]} // end html

Wir können uns dieses Objekt als unser virtuelles DOM vorstellen. Wie das ursprüngliche DOM ist es eine objektbasierte Darstellung unseres HTML-Dokuments. Da es sich aber um ein einfaches Javascript-Objekt handelt, können wir es frei und häufig manipulieren, ohne das eigentliche DOM zu berühren, bis wir es brauchen.

Anstatt ein Objekt für das gesamte Objekt zu verwenden, ist es üblicher, mit kleinen Abschnitten des virtuellen DOM zu arbeiten. Zum Beispiel können wir an einer list-Komponente arbeiten, die unserem ungeordneten Listenelement entspricht.

const list = { tagName: "ul", attributes: { "class": "list" }, children: };

Unter der Haube des virtuellen DOM

Nachdem wir nun gesehen haben, wie ein virtuelles DOM aussieht, wie funktioniert es, um die Leistungs- und Benutzerfreundlichkeitsprobleme des DOM zu lösen?

Wie ich bereits erwähnt habe, können wir das virtuelle DOM verwenden, um die spezifischen Änderungen, die am DOM vorgenommen werden müssen, herauszufiltern und diese spezifischen Aktualisierungen allein durchzuführen. Kehren wir zu unserem Beispiel einer ungeordneten Liste zurück und nehmen wir die gleichen Änderungen vor, die wir mit der DOM-API vorgenommen haben.

Als erstes würden wir eine Kopie des virtuellen DOM erstellen, die die Änderungen enthält, die wir vornehmen wollen. Da wir die DOM-APIs nicht verwenden müssen, können wir einfach ein neues Objekt erstellen.

const copy = { tagName: "ul", attributes: { "class": "list" }, children: };

Dieses copy wird verwendet, um einen sogenannten „Diff“ zwischen dem ursprünglichen virtuellen DOM, in diesem Fall list, und dem aktualisierten Objekt zu erstellen. Ein Diff könnte etwa so aussehen:

const diffs = 

Dieses Diff liefert Anweisungen, wie das tatsächliche DOM zu aktualisieren ist. Sobald alle Diffs gesammelt sind, können wir Änderungen am DOM in Stapeln vornehmen und nur die Aktualisierungen vornehmen, die benötigt werden.

Zum Beispiel könnten wir eine Schleife durch jeden Diff machen und entweder ein neues Kind hinzufügen oder ein altes aktualisieren, je nachdem, was der Diff angibt.

const domElement = document.getElementsByClassName("list");diffs.forEach((diff) => { const newElement = document.createElement(diff.newNode.tagName); /* Add attributes ... */ if (diff.oldNode) { // If there is an old version, replace it with the new version domElement.replaceChild(diff.newNode, diff.index); } else { // If no old version exists, create a new node domElement.appendChild(diff.newNode); }})

Bitte beachten Sie, dass dies eine sehr vereinfachte und abgespeckte Version davon ist, wie ein virtuelles DOM funktionieren könnte, und es gibt viele Fälle, die ich hier nicht behandelt habe.

Das virtuelle DOM und Frameworks

Es ist üblicher, mit dem virtuellen DOM über ein Framework zu arbeiten, anstatt es direkt anzusprechen, wie ich es im obigen Beispiel gezeigt habe.

Frameworks wie React und Vue nutzen das virtuelle DOM-Konzept, um performantere Aktualisierungen des DOMs durchzuführen. Zum Beispiel kann unsere list-Komponente in React folgendermaßen geschrieben werden.

import React from 'react';import ReactDOM from 'react-dom';const list = React.createElement("ul", { className: "list" }, React.createElement("li", { className: "list__item" }, "List item"));ReactDOM.render(list, document.body);

Wenn wir unsere Liste aktualisieren wollten, könnten wir einfach die gesamte Listenvorlage neu schreiben und ReactDOM.render() erneut aufrufen, wobei wir die neue Liste übergeben.

const newList = React.createElement("ul", { className: "list" }, React.createElement("li", { className: "list__item" }, "List item one"), React.createElement("li", { className: "list__item" }, "List item two"););setTimeout(() => ReactDOM.render(newList, document.body), 5000);

Da React das virtuelle DOM verwendet, werden nur die Teile aktualisiert, die sich tatsächlich ändern, auch wenn wir die gesamte Vorlage neu rendern. Wenn wir unsere Entwicklertools betrachten, wenn die Änderung stattfindet, sehen wir die spezifischen Elemente und die spezifischen Teile der Elemente, die sich ändern.

Das DOM vs. das virtuelle DOM

Zusammenfassend lässt sich sagen, dass das virtuelle DOM ein Werkzeug ist, das es uns ermöglicht, mit DOM-Elementen auf eine einfachere und performantere Weise zu interagieren. Es handelt sich um eine Javascript-Objektdarstellung des DOM, die wir so oft wie nötig ändern können. Änderungen, die an diesem Objekt vorgenommen werden, werden dann gesammelt, und Änderungen an der tatsächlichen DOM werden gezielt und seltener vorgenommen.