Warum soll Reacts Konzept von Virtual DOM leistungsfähiger sein als die Überprüfung schmutziger Modelle?

372

Ich habe einen React Dev Talk bei gesehen ( Pete Hunt: React: Best Practices überdenken - JSConf EU 2013 ) und der Redner erwähnte, dass das Dirty-Checking des Modells langsam sein kann. Aber ist die Berechnung des Unterschieds zwischen virtuellen DOMs nicht tatsächlich noch weniger leistungsfähig, da das virtuelle DOM in den meisten Fällen größer als das Modell sein sollte?

Ich mag die potenzielle Leistung des virtuellen DOM (insbesondere das serverseitige Rendern) sehr, aber ich würde gerne alle Vor- und Nachteile kennen.

Daniil
quelle
Ich denke, Sie könnten diesen Vortrag auch auf youtube.com/watch?v=-DX3vJiqxm4 erwähnen, wo er speziell über Benchmarks spricht.
Inafalcao

Antworten:

493

Ich bin der Hauptautor eines Virtual-Dom- Moduls, sodass ich möglicherweise Ihre Fragen beantworten kann. Es gibt tatsächlich 2 Probleme, die hier gelöst werden müssen

  1. Wann rendere ich neu? Antwort: Wenn ich feststelle, dass die Daten verschmutzt sind.
  2. Wie rendere ich effizient neu? Antwort: Verwenden eines virtuellen DOM zum Generieren eines realen DOM-Patches

In React hat jede Ihrer Komponenten einen Status. Dieser Status ähnelt einem beobachtbaren Status, den Sie möglicherweise in Knockout- oder anderen MVVM-Bibliotheken finden. Im Wesentlichen weiß React wann die Szene neu gerendert werden muss, da es beobachten kann, wann sich diese Daten ändern. Die schmutzige Prüfung ist langsamer als die beobachtbaren Werte, da Sie die Daten in regelmäßigen Abständen abfragen und alle Werte in der Datenstruktur rekursiv prüfen müssen. Im Vergleich dazu signalisiert das Festlegen eines Werts für den Status einem Listener, dass sich ein Status geändert hat, sodass React einfach auf Änderungsereignisse für den Status warten und das erneute Rendern in die Warteschlange stellen kann.

Das virtuelle DOM wird zum effizienten erneuten Rendern des DOM verwendet. Dies hängt nicht wirklich mit der schmutzigen Überprüfung Ihrer Daten zusammen. Sie können mithilfe eines virtuellen DOM mit oder ohne Dirty Checking erneut rendern. Sie haben Recht damit, dass die Berechnung des Unterschieds zwischen zwei virtuellen Bäumen einen gewissen Aufwand bedeutet. Beim virtuellen DOM-Unterschied geht es jedoch darum, zu verstehen, was im DOM aktualisiert werden muss und nicht, ob sich Ihre Daten geändert haben oder nicht. Tatsächlich ist der Diff-Algorithmus selbst ein Dirty Checker, aber er wird verwendet, um festzustellen, ob das DOM stattdessen Dirty ist.

Wir möchten den virtuellen Baum nur dann neu rendern, wenn sich der Status ändert. Die Verwendung eines Observable zur Überprüfung, ob sich der Status geändert hat, ist eine effiziente Methode, um unnötiges erneutes Rendern zu verhindern, was zu vielen unnötigen Baumunterschieden führen würde. Wenn sich nichts geändert hat, tun wir nichts.

Ein virtuelles DOM ist schön, weil wir damit unseren Code so schreiben können, als würden wir die gesamte Szene neu rendern. Hinter den Kulissen möchten wir eine Patch-Operation berechnen, die das DOM aktualisiert, um zu sehen, wie wir es erwarten. Obwohl der virtuelle DOM-Diff / Patch-Algorithmus wahrscheinlich nicht die optimale Lösung ist , bietet er uns eine sehr gute Möglichkeit, unsere Anwendungen auszudrücken. Wir erklären einfach genau, was wir wollen und React / virtual-dom wird herausfinden, wie Ihre Szene so aussehen kann. Wir müssen keine manuelle DOM-Manipulation durchführen oder uns über den vorherigen DOM-Status verwirren. Wir müssen auch nicht die gesamte Szene neu rendern, was viel weniger effizient sein könnte als das Patchen.

Matt Esch
quelle
1
Führt React eine schmutzige Überprüfung der Komponentenstützen durch? Ich frage, weil es keine setProps () -Funktion gibt.
Bennlich
1
Was wäre ein Beispiel dafür unnecessary re-renders?
vsync
9
Wenn Sie sagen "Der virtuelle DOM-Diff / Patch-Algorithmus ist wahrscheinlich nicht die optimale Lösung", haben Sie dann eine theoretisch optimalere Lösung im Sinn?
CMCDragonkai
3
Dies scheint die Frage nicht ganz zu beantworten. Für React müssen Sie setState verwenden, um zu signalisieren, dass sich der Status geändert hat. Wenn Sie dazu in der Lage this.state.cats = 99wären, müssten Sie immer noch eine schmutzige Prüfung durchführen, um nach dem Modellwechsel zu suchen, genau wie Angular schmutzig den $ scope-Baum prüft. Dies ist kein Vergleich der Geschwindigkeit der beiden Techniken, sondern lediglich eine Aussage, dass React keine Dirty-Checks durchführt, da es stattdessen einen Backbone-Style-Setter hat.
Superluminary
133

Ich habe kürzlich einen ausführlichen Artikel über den Diff-Algorithmus von React hier gelesen: http://calendar.perfplanet.com/2013/diff/ . Nach meinem Verständnis macht React schnell:

  • Batch-DOM-Lese- / Schreibvorgänge.
  • Effiziente Aktualisierung nur des Unterbaums.

Im Vergleich zu Dirty-Check sind die Hauptunterschiede IMO:

  1. Modell-Dirty-Checking : Die React-Komponente wird immer explizit als Dirty festgelegtsetState Aufruf , sodass hier kein Vergleich (der Daten) erforderlich ist. Bei der Schmutzprüfung erfolgt der Vergleich (der Modelle) immer in jeder Digest-Schleife.

  2. DOM-Aktualisierung : DOM-Vorgänge sind sehr teuer, da durch Ändern des DOM auch CSS-Stile und -Layouts angewendet und berechnet werden. Die durch unnötige DOM-Änderungen gesparte Zeit kann länger sein als die Zeit, die für die Abweichung vom virtuellen DOM aufgewendet wird.

Der zweite Punkt ist noch wichtiger für nicht triviale Modelle wie eines mit einer großen Anzahl von Feldern oder einer großen Liste. Eine Feldänderung des komplexen Modells führt dazu, dass anstelle der gesamten Ansicht / Vorlage nur die Operationen ausgeführt werden, die für DOM-Elemente erforderlich sind, an denen dieses Feld beteiligt ist.

Tungd
quelle
1
Eigentlich habe ich auch einige Artikel gelesen, also wollte ich jetzt (zumindest im Allgemeinen), wie es funktioniert, nur herausfinden, warum es effizienter sein kann als eine schmutzige Überprüfung des Modells. Und 1) Yup, es nicht zu vergleichen , Modelle , aber nicht zu vergleichen , viel größeren virtuellen dom 2) Dirty-Check von Modell uns mit der Fähigkeit liefert nur zu aktualisieren , was auch gebraucht (wie Angular des Fall ist)
Daniil
Ich glaube, dass nur Teile des virtuellen DOM, die der geänderten Komponente entsprechen, verglichen werden müssen, während bei jeder Digest-Schleife für jeden Wert in jedem Bereich eine Schmutzprüfung durchgeführt wird, auch wenn sich nichts geändert hat. Wenn sich große Datenmengen ändern, ist Virtual DOM weniger effizient, jedoch nicht für kleine Datenänderungen.
Tungd
1
Apropos Angular: Da Beobachter den Status auch während des Digests ändern können, wird der Status $scope.$digestmehrmals pro Digest-Zyklus ausgeführt, sodass der vollständige Datenvergleich mehrmals im Vergleich zum einmaligen teilweisen Vergleich des virtuellen DOM-Baums erfolgt.
Tungd
4
Es ist traurig, dass so viele intelligente Entwickler "Berge" von Tricks erfinden, um mit "langsamem" DOM ​​usw. umzugehen, anstatt unsere gemeinsame Aufmerksamkeit darauf zu richten, nur die Browser selbst zu reparieren und uns ein für alle Mal von der Langsamkeit des DOM zu befreien. Es ist, als würde man alle Ressourcen der Menschheit nutzen, um nach Wegen zu suchen, um mit Krebs umzugehen und das Leben eines Patienten zu verbessern, anstatt nur den Krebs selbst zu reparieren. Lächerlichkeiten.
vsync
@vsync Das DOM muss Inhalte auf dem Bildschirm anzeigen. Ein virtuelles DOM nicht. Selbst mit einem DOM mit idealer Leistung ist das Erstellen eines virtuellen DOM schneller.
Jehan
75

Ich mag die potenzielle Leistung des virtuellen DOM (insbesondere das serverseitige Rendern) sehr, aber ich würde gerne alle Vor- und Nachteile kennen.

- OP

React ist nicht die einzige DOM-Manipulationsbibliothek. Ich ermutige Sie, die Alternativen zu verstehen, indem Sie diesen Artikel aus Auth0 lesen , der detaillierte Erklärungen und Benchmarks enthält. Ich werde hier ihre Vor- und Nachteile hervorheben, wie Sie gefragt haben:

Virtuelles DOM von React.js

Geben Sie hier die Bildbeschreibung ein

PROS

  • Schneller und effizienter "Diffing" -Algorithmus
  • Mehrere Frontends (JSX, Hyperscript)
  • Leicht genug, um auf mobilen Geräten ausgeführt zu werden
  • Viel Traktion und Mindshare
  • Kann ohne Reaktion verwendet werden (dh als unabhängiger Motor)

Nachteile

  • Vollständige In-Memory-Kopie des DOM (höhere Speichernutzung)
  • Keine Unterscheidung zwischen statischen und dynamischen Elementen

Ember.js 'Schimmer

Geben Sie hier die Bildbeschreibung ein

PROS

  • Schneller und effizienter Diffing-Algorithmus
  • Unterscheidung zwischen statischen und dynamischen Elementen
  • 100% kompatibel mit der Ember-API (Sie erhalten die Vorteile ohne größere Aktualisierungen Ihres vorhandenen Codes)
  • Leichte In-Memory-Darstellung des DOM

Nachteile

  • Soll nur in Ember verwendet werden
  • Nur ein Frontend verfügbar

Inkrementelles DOM

Geben Sie hier die Bildbeschreibung ein

PROS

  • Reduzierte Speichernutzung
  • Einfache API
  • Einfache Integration in viele Frontends und Frameworks (von Anfang an als Template-Engine-Backend gedacht)

Nachteile

  • Nicht so schnell wie andere Bibliotheken (dies ist fraglich, siehe die Benchmarks unten)
  • Weniger Mindshare und Community-Nutzung
Falsarella
quelle
Die Darstellung der DOM-Manipulation von ReactJS scheint mir wenig zu stören. Das virtuelle DOM des ReactJS ändert sich vollständig, nicht das tatsächliche DOM - richtig? Ich schaue auf den Originalartikel, auf den der Artikel verweist, und hier ist, was ich sehe - teropa.info/images/onchange_vdom_change.svg . teropa.info/blog/2015/03/02/…
smile.al.d.way
35

Hier ist ein Kommentar von React-Teammitglied Sebastian Markbåge, der etwas Licht ins Dunkel bringt:

React unterscheidet die Ausgabe (ein bekanntes serialisierbares Format, DOM-Attribute). Dies bedeutet, dass die Quelldaten ein beliebiges Format haben können. Es kann sich um unveränderliche Datenstrukturen und Zustände innerhalb von Schließungen handeln.

Das Angular-Modell bewahrt keine referenzielle Transparenz und ist daher von Natur aus veränderbar. Sie mutieren das vorhandene Modell, um Änderungen zu verfolgen. Was ist, wenn Ihre Datenquelle jedes Mal unveränderliche Daten oder eine neue Datenstruktur ist (z. B. eine JSON-Antwort)?

Dirty Checking und Object.observe funktionieren nicht für den Status des Abschlussbereichs.

Diese beiden Dinge beschränken sich offensichtlich sehr auf funktionale Muster.

Wenn die Komplexität Ihres Modells zunimmt, wird es außerdem immer teurer, Dirty Tracking durchzuführen. Wenn Sie sich jedoch wie React nur im visuellen Baum unterscheiden, wächst dieser nicht so stark, da die Datenmenge, die Sie zu einem bestimmten Zeitpunkt auf dem Bildschirm anzeigen können, durch Benutzeroberflächen begrenzt ist. Petes Link oben behandelt mehr der Perf-Vorteile.

https://news.ycombinator.com/item?id=6937668

Sophie Alpert
quelle
2
Eigentlich zum letzten Absatz: Es sollte falsch sein: Modell ist größer als virtueller Dom, da für jeden Modellwert (in den meisten Fällen) mindestens ein virtuelles Dom-Element vorhanden ist (und normalerweise viel mehr als eines). Warum möchte ich ein Modell, das nicht angezeigt wird?
Daniil
2
Zwischengespeicherte Sammlungen paginieren.
Kentor
-2

Virtual Dom wird nicht durch Reagieren erfunden. Es ist Teil von HTML dom. Es ist leichtgewichtig und von den browserspezifischen Implementierungsdetails getrennt.

Wir können virtuelles DOM als lokale und vereinfachte Kopie des HTML-DOM von React betrachten. Es ermöglicht React, seine Berechnungen in dieser abstrakten Welt durchzuführen und die „echten“ DOM-Operationen zu überspringen, die oft langsam und browserspezifisch sind. Tatsächlich gibt es keinen großen Unterschied zwischen DOM und VIRTUAL DOM.

Nachfolgend sind die Punkte aufgeführt, warum Virtual Dom verwendet wird ( virtuelles Quell- DOM in ReactJS ):

Wenn Sie das tun:

document.getElementById('elementId').innerHTML = "New Value" Following thing happens:
  1. Der Browser muss den HTML-Code analysieren
  2. Es entfernt das untergeordnete Element von elementId
  3. Aktualisiert den DOM-Wert mit einem neuen Wert
  4. Berechnen Sie das CSS für Eltern und Kind neu
  5. Aktualisieren Sie das Layout, dh die genauen Koordinaten der einzelnen Elemente auf dem Bildschirm
  6. Durchlaufen Sie den Renderbaum und malen Sie ihn in der Browseranzeige

Die Neuberechnung des CSS und geänderter Layouts verwendet einen komplexen Algorithmus und wirkt sich auf die Leistung aus.

Sowie das Aktualisieren der DOM-Eigenschaften, dh. Werte. Es folgt einem Algorithmus.

Angenommen, Sie aktualisieren DOM 10 Mal direkt, dann werden alle oben genannten Schritte einzeln ausgeführt, und das Aktualisieren von DOM-Algorithmen benötigt Zeit, um die DOM-Werte zu aktualisieren.

Aus diesem Grund ist Real DOM langsamer als Virtual DOM.

Hemant Nagarkoti
quelle
3
Wenn Sie in diesem Beispiel den Dom direkt oder über einen virtuellen Dom ändern, ändern Sie schließlich in beiden Fällen den Dom.
Magallanes
Ja, in beiden Fällen aktualisieren wir dom, aber im Fall von virtuellem dom aktualisiert es nur das Schlüsselfeld oder das Element-Tag (eindeutig definiert durch unterscheidet den Algorithmus von reagieren). Während das Aktualisieren von Dom-Updates oder das vollständige Aktualisieren des gesamten Dom.
Hemant Nagarkoti
11
Ich habe diesen Artikel von hackernoon.com/virtual-dom-in-reactjs-43a3fdb1d130 gesehen . Vielleicht ist es besser, auf die Quelle hinzuweisen, wenn Sie nicht der Autor sind.
Jinggang
2
"Aus diesem Grund ist Real DOM langsamer als Virtual DOM." Nein, Sir, Sie liegen einfach falsch.
Roecrew