Wie implementiert AngularJS seinen bidirektionalen Datenbindungsmechanismus?

8

Mit AngularJS können Sie eine bidirektionale Datenbindung implementieren. Der interessante Teil ist jedoch, wie er Modelländerungen erkennt? Das Modell ist normalerweise ein einfaches Objekt wie der folgende Code. Wir können die name-Eigenschaft von $scope.user ändern, aber wie erkennt AngularJS das Modell? Zeigt AngularJS alle Eigenschaften des Objekts $scope an?

%Vor%     
mind1n 24.05.2015, 15:13
quelle

3 Antworten

10

Es gibt einen Digest-Zyklus, in dem der Bereich alle $ watch-Ausdrücke untersucht und sie mit dem vorherigen Wert vergleicht. Wenn der alte Wert nicht mit dem neuen Wert übereinstimmt, wird AngularJS die entsprechenden Stellen aktualisieren, a.k.a dreckige Prüfung.

Damit der Digest-Zyklus ausgeführt werden kann, muss $apply(fn) ausgeführt werden. So gelangen Sie in die Angular-Welt von JavaScript. Wie wird $apply(fn) aufgerufen (aus AngularJs Integration mit dem Browser ) ):

  1. Die Ereignisschleife des Browsers wartet auf das Eintreffen eines Ereignisses. Ein Ereignis ist eine Benutzerinteraktion, ein Timer-Ereignis oder ein Netzwerkereignis (Antwort von einem Server).
  2. Der Rückruf des Ereignisses wird ausgeführt. Dies tritt in den JavaScript-Kontext ein. Der Rückruf kann die DOM-Struktur ändern.
  3. Sobald der Callback ausgeführt wird, verlässt der Browser den JavaScript-Kontext und rendert die Ansicht basierend auf DOM-Änderungen neu.

Datenbindung

Erläuterung des Auswertungszyklus

Um eine bidirektionale Bindung zu erreichen, registrieren Direktiven Beobachter. Damit eine Seite schnell und effizient ist, müssen wir versuchen, alle diese von uns erstellten Beobachter zu reduzieren. Sie sollten also vorsichtig sein, wenn Sie eine Zweiwege-Bindung verwenden - d. H. Verwenden Sie sie nur, wenn Sie sie wirklich benötigen. Ansonsten Einweg verwenden:

<h1> {{ ::vm.title }} </h1>

Hier ist es ziemlich offensichtlich, dass der Titel der Seite wahrscheinlich nicht geändert wird, während sich der Benutzer auf der Seite befindet - oder er muss den neuen sehen, wenn er geändert wird. So können wir :: verwenden, um eine unidirektionale Bindung während der Template-Verknüpfungsphase zu registrieren.

Die Hauptprobleme, die ich bei Explosionen von Beobachtern gesehen habe, sind Gitter mit Hunderten von Reihen. Wenn diese Zeilen ziemlich viele Spalten haben und in jeder Zelle eine Zweiwege-Datenbindung besteht, dann ist es ein Vergnügen. Sie können sich zurücklehnen und warten, bis die Seite geladen ist!

    
Callum Linington 24.05.2015 15:16
quelle
7

Zwei-Wege-Bindung beschränkt sich fast ausschließlich auf Elemente, die ng-model verwenden. Die Richtung, die von Ansicht zu Modell geht, verwendet Standard-Event-Handler, um Änderungen zu erkennen, die innerhalb des Modells aktualisiert werden müssen (z. B. onchange ). Die Richtung vom Modell zurück zur Ansicht wird während eines $digest aktualisiert. Aber wir rufen $digest nicht direkt auf.

Jedes Element auf Ihrer Seite, das auf den Digest-Zyklus reagiert, fügt irgendwo einen Listener und einen Ausdruck an seinen Bereich mit $watch an. Wenn Sie {{ foo() }} schreiben oder ng-model='user.name' verwenden, wird intern ein Aufruf von $watch in Ihrem Namen mit einem Javascript-Ausdruck aufgerufen, der jedes Mal ausgeführt wird, wenn ein Digest-Zyklus ausgeführt wird. Diese Registrierung kann während der Kompilierung der Vorlage (unserem ersten Beispiel) oder während der Linkphase einer Direktive (unserer zweiten) erfolgen.

Hier gibt es keine Magie. Die angehängten Listener sind reguläre Funktionen - in unserem Beispiel wird der Listener für den Ausdruck foo() bereitgestellt und der HTML-Text auf der Seite aktualisiert, während der Listener für den Ausdruck user.name % aufruft. co_de% oder setText oder was auch immer von der bestimmten Eingabe verlangt wird, an die setOption angehängt wurde.

Obwohl eckig die meisten Abhörmaßnahmen bewältigen kann, können Sie Ihre eigenen Abhörmusik mit Ihren eigenen Zuhörern manuell in jeder Funktion mit Zugriff auf einen Bereich anhängen (der Bereich ist wichtig, da wir diese Beobachter abreißen, wenn die entsprechenden Teile der Seite werden entfernt). Achte auf den Überschuss. Bindungen sind nicht frei und je mehr Dinge gebunden sind, desto langsamer reagiert die Seite. Einmalige Bindungen sind eine Möglichkeit, diese Kosten zu reduzieren. Die Verwendung von ng-model mit $on und $emit ist ein weiteres.

Also wann heißt Digest? Es ist sicherlich nicht automatisch. Wenn der Digest-Zyklus ausgeführt wird, bedeutet dies, dass irgendwo in ihrem Bereich oder im Stammbereich ein Name namens $broadcast steht. $apply fügt Handler hinzu, die auf normale HTML-Ereignisse reagieren und in Ihrem Auftrag Aufrufe von ng-model vornehmen. Aber $apply , auf der anderen Seite, wird niemals aufgerufen werden, bis irgendwo ein anderes Skript irgendwo foo() aufruft. Glücklicherweise füllen die meisten Funktionen, die Sie für eckigen Zeilenumbruch ausfüllen, diese Funktionen mit einem Aufruf von $apply , so dass Sie den Aufruf nicht oft selbst durchführen müssen (zB $apply wird mit $timeout umschlossen, weshalb wir benutze es anstelle von $apply ). Wenn Sie jedoch etwas außerhalb des Bereichs von angular verwenden (eine Bibliothek von Drittanbietern, die sich mit Ereignissen verbindet), müssen Sie daran denken, setTimeout selbst aufzurufen, und wie oben können Sie dies manuell tun, indem Sie $apply aufrufen. überall, wo Sie Zugriff auf einen Bereich haben.

    
Michael Hays 24.05.2015 16:17
quelle
1

Um die Datenbindung zu ermöglichen, verwendet AngularJS $ watch-APIs, um die Änderungen am Bereich zu beobachten. AngularJS registrierte Beobachter für jede Variable im Bereich, um den Wert darin zu beobachten. Wenn der Wert der Variablen im Bereich geändert wird, wird die Ansicht automatisch aktualisiert.

Es passiert, weil der $ Digest-Zyklus ausgelöst wird. Daher verarbeitet AngularJS alle registrierten Beobachter des aktuellen Bereichs und der untergeordneten Elemente und sucht nach den Aktualisierungen und ruft die dedizierten Überwachungslistener auf, bis das Modell stabilisiert ist und keine weiteren Listener ausgelöst werden. Sobald die $ digest-Schleife die Ausführung beendet hat, rendert der Browser das DOM erneut und spiegelt die Änderungen wider.

Standardmäßig wird jede Variable in einem Bereich durch den Winkel beobachtet. Auf diese Weise werden unnötige Variablen auch durch den Winkel beobachtet, was zeitaufwendig ist und als Ergebnis dazu führt, dass die Seite langsam wird.

    
Deepak Khantwal 05.12.2016 06:19
quelle