2015-03-16 2 views
9

Ich bin neu in Angular, aber ich habe schon gehört (und read) einige "Gerüchte" über sein Rendering-Modell und wie es anders ist als zum Beispiel React.Verwendet Angular DOM diffing oder muss es jedes Listenelement "neu rendern"?

Ich habe einige Beiträge von Angular-Experten gelesen, die behaupten, dass, wenn Sie lange Listen mit Angular rendern müssen, es langsam sein könnte, weil Angular die gesamte Liste neu rendern würde, wenn sich etwas ändert, während React (zum Beispiel) msgstr "" "wird die gesamte Liste nicht von Grund auf neu rendern, wenn sie bereits gerendert wurde, aber intern werden die gerenderten DOM Elemente nachverfolgt und beim neuen Aufruf wird ein neues virtuelles DOM erstellt, mit dem vorherigen verglichen und nur die Änderungen übernommen"

(von einer zufälligen Blog-Post über Angular Rendering-Probleme zitiert)

so wie ich Angular begann Lernen, war mein erstes, was probiere das aus.

Und es scheint, dass ich das Problem nicht reproduzieren können ...

ist hier ein Dummy Plunker, die ich created das Problem zu reproduzieren.

Sie neue Elemente zu einer Liste von Nachrichten hinzufügen können, die mit gerendert ng-repeat wie folgt aus:

<table> 
    <tr ng-repeat="m in messages" class="{{name}}"> 
    <td>{{m.message}}</td> 
    <td>{{m.date}}</td> 
    </tr> 
</table> 

Sie auf eine Schaltfläche klicken können, die ein solches Element nicht aktualisieren, und Sie können eine andere Eigenschaft aktualisieren Das ist völlig unabhängig von der Liste (name)

Jetzt, wenn ich Developer Toolbar öffnen und HTML-Attribute eines Elements in der Tabelle zu ändern und dann auf "eine neue Nachricht hinzufügen" klicken, gehen meine Änderungen nicht verloren oder mit Angular überschrieben - es scheint, dass Angular das DOM nicht vollständig neu rendert. Es scheint ziemlich schlau zu sein.

Hat Angular in letzter Zeit begonnen, DOM zu verwenden? (Meine Demo verwendet Angular 1.4.0 beta)

Nur weil aus Sicht der DOM-Rendering sehe ich nur nicht den großen Unterschied zwischen React und Angular.

Können Sie mir einen Anwendungsfall zeigen, der den Nachteil von Angulars Rendering-Modell zeigt?

+4

Das scheint mir nicht "zu breit". Die primäre Frage, die das OP stellt, ist über eine * spezifische * Mechanik von Angular .. – user2864740

+3

Ihre Fragen sind ein bisschen breit, weil es wirklich einige Fragen stellt, und möglicherweise eine bessere Passform auf Programmers SE. Wie auch immer, Angular unterscheidet sich nicht wie React, aber ng-repeat hält mit dem, was es wiederholt, und den damit verbundenen Elementen Schritt. Es wird nur ändern, was geändert werden muss. Siehe die Option 'track by' von' ng-repeat'. Die Tracking-Effizienz von Angular in dieser Hinsicht ist der Grund, warum Duplikate in 'ng-repeat' nicht erlaubt sind, es sei denn, Sie verwenden die' track by'-Option, um zu ändern, welche Angular-Uhren die Dinge synchron halten. – m59

+5

Die Wahrheit über Blog-Posts zu untersuchen, die unbestätigte Behauptungen über bestimmte Technologien aufstellen, ist nicht wirklich unsere Spezialität und auch nicht die Spezialität von Programmers.SE. –

Antwort

6

Es gibt ziemlich viel Verwirrung in Bezug auf dieses Thema, vor allem, weil es nicht eine einfache "eckige Re-Rendern alles" Antwort ist.

Die Basis der eckigen Datenbindung (in 1.x-Versionen) umgibt das Konzept einer $digest Schleife und $scope. $scope ist ein spezielles Objekt, das seine Eigenschaften "selbst nachverfolgt" und einen JavaScript-Ereignis-Listener für jede Eigenschaft mit der Methode $scope.$watch() erstellt. Diese Listener überwachen Änderungen an den veränderbaren Eingabeelementen in HTML und an den $scope Eigenschaften.

Wenn ein JavaScript-Listener ausgelöst wird, durchläuft die Schleife $digest alle Elemente unter $watch und aktualisiert die Werte entsprechend. Sie können auch $scope.$apply() aufrufen, um eine $digest-Schleife manuell auszuführen. Diese Schleife kann mehrere Male ausgeführt werden, da Änderungen an einem Wert sich auf einen anderen Wert unter $watch auswirken können, der einen anderen $digest auslöst. Die $digest-Schleife verfügt jedoch über eine Iterationsbegrenzung, um sicherzustellen, dass sie bei Zirkelreferenzen stoppt.

Die Reibung kommt, wenn Sie mit Arrays von Objekten zu tun haben, und die spezielle Direktive ng-repeat. Standardmäßig überprüft die $watch()-Funktion nur Objektreferenzgleichheit. Innerhalb jedes $digest prüft AngularJS, ob die neuen und alten Werte das gleiche "physische" Objekt sind und ruft nur dann seinen Handler auf, wenn Sie tatsächlich die zugrunde liegende Objektreferenz ändern.

Um dem entgegenzuwirken, erstellt ng-repeat es eigene einzigartige scope. Dies ermöglicht eine eindeutige $watch für jedes Element im Array. Die Herausforderung hier ist, dass, wenn sich das Array selbst ändert, dieses einzigartige scope zusammen mit allen $watch Elementen regeneriert wird. Pushing, Popping, Splicing eines Arrays kann viele $watch Werte erzeugen.

Angular bietet einige Möglichkeiten, mit diesem Problem umzugehen.

Die neue Bind Once-Syntax, die unter 1.3 hinzugefügt wurde, ermöglicht Listener, die nur existieren, bis der Ausdruck ausgewertet wird. ng-repeat="element in ::elements" Durchläuft das Array, füllt das DOM und zerstört dann den Event Listener. Dies ist ideal für Situationen, in denen sich das DOM-Element nach der Auswertung nicht ändert.

Es ist auch möglich, Elemente unter Verwendung von track by aggressiv zu verfolgen. ng-repeat="element in elements track by $id" erstellt einen $watch für den eindeutigen $id-Wert und nicht für die Position des Elements im Array. Dies ermöglicht eine stabilere $watch Ausbreitung und ist ideal in Fällen, in denen sich der Wert des Elements ändern kann.

Warum die Änderungen, die Sie in der Konsole vorgenommen haben, nicht verloren gegangen sind: Erstens werden Änderungen in der Entwicklerkonsole keine Ereignislistener auslösen. Zweitens würde das spezifische DOM-Element, das Sie geändert haben, nur geändert werden, wenn die $watch eine Änderung erkannt hat. Dies ist jedoch nicht wirklich ein "Diff" des HTML; Angular beobachtet nicht den HTML-Code, sondern "beobachtet die Daten" sozusagen.

+0

Ich fühle mich wie ich wiederholte mich zwischen dieser Antwort und der Antwort auf http://stackoverflow.com/questions/29064684/memory-leak-in-ionic-angular/29065924#29065924, aber ich kann nicht helfen, das Gefühl ist, dass dies ist ein komplexes Thema, das eine gründliche Erklärung benötigt. – Claies

+0

Danke für die ausführliche Erklärung! Heute habe ich mehr über Angular erfahren und habe auch mit einigen Angular Experten gesprochen, die das selbe Zeug erzählten, das du in deiner Antwort erwähnt hast. Um die verschiedenen Antworten zusammenzufassen: Die Rendering-Logik von 'ng-repeat' ist einer der am besten optimierten Codes in Angular und aus diesem Grund rendert Angular das gesamte Listenelement nicht naiv neu, wenn ich etwas modifiziere. Wenn es einen Engpass gibt, ist der Engpass wahrscheinlich die Digest-Schleife selbst - die bei jeder Änderung der Eigenschaft über die gesamte Sammlung iteriert. Dies könnte jedoch ein Problem sein. – Zsolt

Verwandte Themen