Wie funktioniert die Datenbindung im AngularJS
Framework?
Ich habe keine technischen Details auf ihrer Website gefunden . Es ist mehr oder weniger klar, wie es funktioniert, wenn Daten von der Ansicht zum Modell weitergegeben werden. Aber wie verfolgt AngularJS Änderungen der Modelleigenschaften ohne Setter und Getter?
Ich fand heraus, dass es JavaScript-Beobachter gibt , die diese Arbeit erledigen können. Sie werden jedoch in Internet Explorer 6 und Internet Explorer 7 nicht unterstützt . Woher weiß AngularJS, dass ich beispielsweise Folgendes geändert und diese Änderung in einer Ansicht wiedergegeben habe?
myobject.myproperty="new value";
javascript
angularjs
data-binding
Pashec
quelle
quelle
Antworten:
AngularJS merkt sich den Wert und vergleicht ihn mit einem vorherigen Wert. Dies ist eine grundlegende Schmutzprüfung. Wenn sich der Wert ändert, wird das Änderungsereignis ausgelöst.
Die
$apply()
Methode, die Sie beim Übergang von einer Nicht-AngularJS-Welt in eine AngularJS-Welt aufrufen, wird aufgerufen$digest()
. Ein Digest ist einfach nur eine alte Drecksprüfung. Es funktioniert in allen Browsern und ist vollständig vorhersehbar.Im Gegensatz zu Dirty-Checking (AngularJS) und Change-Listenern ( KnockoutJS und Backbone.js ): Während Dirty-Checking einfach und sogar ineffizient erscheint (darauf werde ich später noch eingehen), stellt sich heraus, dass es immer semantisch korrekt ist. Während Change Listener viele seltsame Eckfälle haben und Dinge wie Abhängigkeitsverfolgung benötigen, um sie semantisch korrekter zu machen. KnockoutJS-Abhängigkeitsverfolgung ist eine clevere Funktion für ein Problem, das AngularJS nicht hat.
Probleme mit Änderungslistenern:
Was ist mit Leistung?
Es scheint also, dass wir langsam sind, da Dirty-Checking ineffizient ist. Hier müssen wir uns reelle Zahlen ansehen und nicht nur theoretische Argumente haben, sondern zunächst einige Einschränkungen definieren.
Menschen sind:
Langsam - Alles, was schneller als 50 ms ist, ist für den Menschen nicht wahrnehmbar und kann daher als "sofort" betrachtet werden.
Eingeschränkt - Sie können einem Menschen nicht wirklich mehr als 2000 Informationen auf einer einzigen Seite anzeigen. Alles andere ist eine wirklich schlechte Benutzeroberfläche, und Menschen können dies sowieso nicht verarbeiten.
Die eigentliche Frage lautet also: Wie viele Vergleiche können Sie in 50 ms mit einem Browser durchführen? Diese Frage ist schwer zu beantworten, da viele Faktoren ins Spiel kommen. Hier ist jedoch ein Testfall: http://jsperf.com/angularjs-digest/6, mit dem 10.000 Beobachter erstellt werden. In einem modernen Browser dauert dies knapp 6 ms. In Internet Explorer 8 dauert es ungefähr 40 ms. Wie Sie sehen, ist dies heutzutage selbst bei langsamen Browsern kein Problem. Es gibt eine Einschränkung: Die Vergleiche müssen einfach sein, um in das Zeitlimit zu passen ... Leider ist es viel zu einfach, einen langsamen Vergleich in AngularJS einzufügen, sodass es einfach ist, langsame Anwendungen zu erstellen, wenn Sie nicht wissen, was Sie sind sind dabei. Wir hoffen jedoch auf eine Antwort, indem wir ein Instrumentierungsmodul bereitstellen, das Ihnen zeigt, welche Vergleiche langsam sind.
Es stellt sich heraus, dass Videospiele und GPUs den Dirty-Checking-Ansatz verwenden, insbesondere weil er konsistent ist. Solange sie die Bildwiederholfrequenz des Monitors überschreiten (normalerweise 50-60 Hz oder alle 16,6-20 ms), ist jede Leistung darüber eine Verschwendung. Sie sollten also besser mehr Material zeichnen, als die FPS zu erhöhen.
quelle
Misko hat bereits eine hervorragende Beschreibung der Funktionsweise der Datenbindungen gegeben, aber ich möchte meine Meinung zum Leistungsproblem bei der Datenbindung hinzufügen.
Wie Misko feststellte, treten bei etwa 2000 Bindungen Probleme auf, aber Sie sollten ohnehin nicht mehr als 2000 Informationen auf einer Seite haben. Dies mag zutreffen, aber nicht jede Datenbindung ist für den Benutzer sichtbar. Sobald Sie mit dem Erstellen eines Widgets oder Datenrasters mit bidirektionaler Bindung beginnen, können Sie problemlos 2000 Bindungen treffen, ohne eine schlechte UX zu haben.
Stellen Sie sich beispielsweise ein Kombinationsfeld vor, in das Sie Text eingeben können, um die verfügbaren Optionen zu filtern. Diese Art der Steuerung könnte ~ 150 Elemente haben und dennoch sehr gut verwendbar sein. Wenn es eine zusätzliche Funktion hat (zum Beispiel eine bestimmte Klasse für die aktuell ausgewählte Option), erhalten Sie 3-5 Bindungen pro Option. Wenn Sie drei dieser Widgets auf eine Seite setzen (z. B. eines zur Auswahl eines Landes, das andere zur Auswahl einer Stadt in diesem Land und das dritte zur Auswahl eines Hotels), befinden Sie sich bereits zwischen 1000 und 2000 Bindungen.
Oder betrachten Sie ein Datenraster in einer Unternehmenswebanwendung. 50 Zeilen pro Seite sind nicht unangemessen, von denen jede 10 bis 20 Spalten haben kann. Wenn Sie dies mit ng-Wiederholungen erstellen und / oder Informationen in einigen Zellen haben, die einige Bindungen verwenden, können Sie sich allein mit diesem Raster 2000 Bindungen nähern.
Ich finde, dass dies ein großes Problem bei der Arbeit mit AngularJS ist, und die einzige Lösung, die ich bisher finden konnte, besteht darin, Widgets ohne bidirektionale Bindung zu erstellen, anstatt ngOnce zu verwenden, Beobachter und ähnliche Tricks abzumelden oder zu konstruieren Anweisungen, die das DOM mit jQuery- und DOM-Manipulation erstellen. Ich bin der Meinung, dass dies den Zweck der Verwendung von Angular in erster Linie zunichte macht.
Ich würde gerne Vorschläge hören, wie ich damit umgehen kann, aber dann sollte ich vielleicht meine eigene Frage schreiben. Ich wollte dies in einen Kommentar einfügen, aber es stellte sich heraus, dass es viel zu lang dafür war ...
TL; DR
Die Datenbindung kann auf komplexen Seiten zu Leistungsproblemen führen.
quelle
Durch schmutziges Überprüfen des
$scope
ObjektsAngular verwaltet eine einfache
array
Anzahl von Beobachtern in den$scope
Objekten. Wenn Sie eine inspizieren, werden$scope
Sie feststellen, dass sie einenarray
angerufenen enthält$$watchers
.Jeder Beobachter ist ein
object
, der unter anderem enthältattribute
Name oder etwas Komplizierteres sein.$scope
als verschmutzt.Wie Beobachter definiert werden
Es gibt viele verschiedene Möglichkeiten, einen Beobachter in AngularJS zu definieren.
Sie können explizit
$watch
einattribute
ein$scope
.Sie können eine
{{}}
Interpolation in Ihre Vorlage einfügen (ein Beobachter wird aktuell für Sie erstellt$scope
).Sie können eine Anweisung
ng-model
anfordern, um den Beobachter für Sie zu definieren.Das
$digest
Zyklus prüft alle Beobachter auf ihren letzten WertWenn wir mit AngularJS über die normalen Kanäle (ng-model, ng-repeat usw.) interagieren, wird durch die Direktive ein Digest-Zyklus ausgelöst.
Ein Verdauungszyklus ist eine Tiefenüberquerung
$scope
aller seiner Kinder . Für jeden$scope
object
iterieren wir über seine$$watchers
array
und bewerten alle Ausdrücke. Wenn sich der neue Ausdruckswert vom letzten bekannten Wert unterscheidet, wird die Watcher-Funktion aufgerufen. Diese Funktion kann einen Teil des DOM neu kompilieren, einen Wert für neu berechnen$scope
, einen auslösenAJAX
request
, alles, was Sie dazu benötigen.Jeder Bereich wird durchlaufen und jeder Überwachungsausdruck wird ausgewertet und mit dem letzten Wert verglichen.
Wenn ein Beobachter ausgelöst wird,
$scope
ist der verschmutztWenn ein Beobachter ausgelöst wird, weiß die App, dass sich etwas geändert hat, und das
$scope
wird als verschmutzt markiert.Watcher-Funktionen können andere Attribute auf
$scope
oder auf einem übergeordneten Element ändern$scope
. Wenn eine$watcher
Funktion ausgelöst wurde, können wir nicht garantieren, dass unsere andere$scope
noch sauber sind, und führen daher den gesamten Digest-Zyklus erneut aus.Dies liegt daran, dass AngularJS über eine bidirektionale Bindung verfügt, sodass Daten wieder in den
$scope
Baum übertragen werden können. Wir können einen Wert auf einem höheren Wert ändern$scope
, der bereits verdaut wurde. Vielleicht ändern wir einen Wert auf der$rootScope
.Wenn das
$digest
schmutzig ist, führen wir das gesamte aus$digest
Zyklus erneut ausWir durchlaufen den
$digest
Zyklus kontinuierlich, bis entweder der Verdauungszyklus sauber ist (alles$watch
Ausdrücke haben den gleichen Wert wie im vorherigen Zyklus) oder wir das Digest-Limit erreichen. Standardmäßig ist diese Grenze auf 10 festgelegt.Wenn wir das Digest-Limit erreichen, wird AngularJS einen Fehler in der Konsole auslösen:
Der Digest ist hart für die Maschine, aber für den Entwickler einfach
Wie Sie sehen können, überprüft AngularJS jedes Mal, wenn sich in einer AngularJS-App etwas ändert, jeden einzelnen Beobachter in der
$scope
Hierarchie, um zu sehen, wie er reagieren soll. Für einen Entwickler ist dies ein enormer Produktivitätsvorteil, da Sie jetzt fast keinen Verkabelungscode mehr schreiben müssen. AngularJS merkt nur, wenn sich ein Wert geändert hat, und macht den Rest der App mit der Änderung konsistent.Aus Sicht der Maschine ist dies jedoch äußerst ineffizient und verlangsamt unsere App, wenn wir zu viele Beobachter erstellen. Misko hat eine Zahl von ungefähr 4000 Beobachtern angegeben, bevor sich Ihre App in älteren Browsern langsam anfühlt.
Diese Grenze ist leicht zu erreichen, wenn Sie
ng-repeat
über eine großeJSON
array
zum Beispiel . Sie können dem entgegenwirken, indem Sie Funktionen wie die einmalige Bindung zum Kompilieren einer Vorlage verwenden, ohne Beobachter zu erstellen.So vermeiden Sie, dass zu viele Beobachter erstellt werden
Jedes Mal, wenn Ihr Benutzer mit Ihrer App interagiert, wird jeder einzelne Beobachter in Ihrer App mindestens einmal bewertet. Ein großer Teil der Optimierung einer AngularJS-App besteht darin, die Anzahl der Beobachter in Ihrem
$scope
Baum zu reduzieren . Eine einfache Möglichkeit, dies zu tun, ist die einmalige Bindung .Wenn Sie Daten haben, die sich selten ändern, können Sie sie nur einmal mit der :: -Syntax binden, wie folgt:
oder
Die Bindung wird nur ausgelöst, wenn die enthaltene Vorlage gerendert und die Daten geladen wurden
$scope
.Dies ist besonders wichtig, wenn Sie eine
ng-repeat
mit vielen Artikeln haben.quelle
Das ist mein Grundverständnis. Es kann durchaus falsch sein!
$watch
Methode übergeben wird.$apply
Methode umschlossenen Codeblocks vorgenommen werden.$apply
der$digest
Methode wird die Methode aufgerufen, die jede der Uhren durchläuft und prüft, ob sie sich seit dem letzten Ausführen geändert haben$digest
.In der normalen Entwicklung weist die Datenbindungssyntax im HTML den AngularJS-Compiler an, die Uhren für Sie zu erstellen, und die Controller-Methoden werden
$apply
bereits ausgeführt. Für den Anwendungsentwickler ist also alles transparent.quelle
Ich habe mich das eine Weile selbst gefragt. Wie ändert sich ohne Setter
AngularJS
eine Änderung am$scope
Objekt? Fragt es sie ab?Was es tatsächlich tut, ist Folgendes: Jeder "normale" Ort, an dem Sie das Modell ändern, wurde bereits aus dem Bauch heraus aufgerufen
AngularJS
, sodass es automatisch$apply
nach Ihnen ruft , nachdem Ihr Code ausgeführt wurde. Angenommen, Ihr Controller verfügt über eine Methode, dieng-click
an ein Element angeschlossen ist. DaAngularJS
der Aufruf dieser Methode für Sie zusammengeführt wird, besteht die Möglichkeit, eine$apply
an der entsprechenden Stelle durchzuführen. Ebenso werden Ausdrücke, die direkt in den Ansichten angezeigt werden, von ausgeführt,AngularJS
so dass dies der Fall ist$apply
.Wenn in der Dokumentation davon gesprochen wird, dass
$apply
Code außerhalb vonAngularJS
manuell aufgerufen werden muss , handelt es sich um Code, der beim Ausführen nicht vonAngularJS
selbst im Aufrufstapel stammt.quelle
Mit Bildern erklären:
Die Datenbindung erfordert eine Zuordnung
Die Referenz im Bereich ist nicht genau die Referenz in der Vorlage. Wenn Sie zwei Objekte mit Daten binden, benötigen Sie ein drittes, das das erste abhört und das andere ändert.
Wenn Sie das ändern
<input>
, berühren Sie hier die Datenreferenz3 . Und die klassische Daten-bind mecanism ändert Daten ref4 . Wie{{data}}
bewegen sich die anderen Ausdrücke?Ereignisse führen zu $ Digest ()
Angular behält eine
oldValue
undnewValue
von jeder Bindung bei. Und nach jedem Angular-Ereignis$digest()
überprüft die berühmte Schleife die WatchList, um festzustellen, ob sich etwas geändert hat. Diese Winkel Ereignisse sindng-click
,ng-change
,$http
abgeschlossen ... Die$digest()
Schleife wird solange irgendwelchenoldValue
unterscheidet sich von dernewValue
.Im vorherigen Bild wird festgestellt, dass sich Datenreferenz1 und Datenreferenz2 geändert haben.
Schlussfolgerungen
Es ist ein bisschen wie das Ei und Huhn. Man weiß nie, wer anfängt, aber hoffentlich funktioniert es die meiste Zeit wie erwartet.
Der andere Punkt ist, dass Sie die Auswirkungen einer einfachen Bindung auf den Speicher und die CPU leicht verstehen können. Hoffentlich sind Desktops fett genug, um damit umzugehen. Handys sind nicht so stark.
quelle
Offensichtlich gibt es keine regelmäßige Überprüfung,
Scope
ob sich Änderungen an den damit verbundenen Objekten ergeben. Nicht alle an den Bereich angehängten Objekte werden überwacht. Scope unterhält prototypisch einen $$ Beobachter .Scope
durchläuft dies nur,$$watchers
wenn$digest
es aufgerufen wird.Angular fügt den $$ -Betrachtern für jeden dieser einen Beobachter hinzu
Die $ watch- Funktion akzeptiert drei Parameter:
In Angular gibt es eine interessante Sache namens Digest Cycle. Der $ Digest-Zyklus beginnt als Ergebnis eines Aufrufs von $ scope. $ Digest (). Angenommen, Sie ändern ein $ scope-Modell in einer Handlerfunktion über die Direktive ng-click. In diesem Fall löst AngularJS automatisch einen $ Digest-Zyklus aus, indem $ Digest () aufgerufen wird. Zusätzlich zu ng-click gibt es mehrere andere integrierte Anweisungen / Dienste, mit denen Sie Modelle ändern können (z. B. ng-model, $ timeout usw.). und automatisch einen $ Digest-Zyklus auslösen. Die grobe Implementierung von $ Digest sieht so aus.
Wenn wir die Funktion setTimeout () von JavaScript verwenden, um ein Bereichsmodell zu aktualisieren, kann Angular nicht wissen, was Sie möglicherweise ändern. In diesem Fall liegt es in unserer Verantwortung, $ apply () manuell aufzurufen, wodurch ein $ Digest-Zyklus ausgelöst wird. Wenn Sie eine Direktive haben, die einen DOM-Ereignis-Listener einrichtet und einige Modelle innerhalb der Handler-Funktion ändert, müssen Sie $ apply () aufrufen, um sicherzustellen, dass die Änderungen wirksam werden. Die große Idee von $ apply ist, dass wir Code ausführen können, der Angular nicht kennt. Dieser Code kann möglicherweise noch Änderungen am Gültigkeitsbereich vornehmen. Wenn wir diesen Code in $ apply einschließen, wird $ digest () aufgerufen. Grobe Implementierung von $ apply ().
quelle
AngularJS verarbeitet den Datenbindungsmechanismus mithilfe von drei leistungsstarken Funktionen: $ watch () , $ Digest () und $ apply () . Meistens ruft AngularJS die Bereiche $ scope. $ Watch () und $ scope. $ Digest () auf. In einigen Fällen müssen Sie diese Funktionen jedoch möglicherweise manuell aufrufen, um sie mit neuen Werten zu aktualisieren.
$ watch () : -
$ Digest () -
$ apply () -
quelle
Es kam vor, dass ich ein Datenmodell einer Person mit einem Formular verknüpfen musste. Ich habe eine direkte Zuordnung der Daten zum Formular vorgenommen.
Zum Beispiel, wenn das Modell so etwas wie:
Die Steuereingabe des Formulars:
Auf diese Weise wird dies automatisch in der Ansicht angezeigt, wenn Sie den Wert des Objektcontrollers ändern.
Ein Beispiel, bei dem ich das Modell übergeben habe, wird aus Serverdaten aktualisiert, wenn Sie nach einer Postleitzahl und einer Postleitzahl fragen, die auf schriftlichen Ladevorgängen basieren, eine Liste der dieser Ansicht zugeordneten Kolonien und Städte erstellen und standardmäßig den ersten Wert mit dem Benutzer festlegen. Und das habe ich sehr gut gemacht. Was passiert, ist, dass es
angularJS
manchmal einige Sekunden dauert, um das Modell zu aktualisieren. Dazu können Sie einen Spinner einsetzen, während Sie die Daten anzeigen.quelle
Die Einweg-Datenbindung ist ein Ansatz, bei dem ein Wert aus dem Datenmodell entnommen und in ein HTML-Element eingefügt wird. Es gibt keine Möglichkeit, das Modell aus der Ansicht zu aktualisieren. Es wird in klassischen Vorlagensystemen verwendet. Diese Systeme binden Daten nur in eine Richtung.
Die Datenbindung in Angular-Apps ist die automatische Synchronisierung von Daten zwischen den Modell- und Ansichtskomponenten.
Mit der Datenbindung können Sie das Modell als die einzige Quelle der Wahrheit in Ihrer Anwendung behandeln. Die Ansicht ist jederzeit eine Projektion des Modells. Wenn das Modell geändert wird, spiegelt die Ansicht die Änderung wider und umgekehrt.
quelle
Hier ist ein Beispiel für die Datenbindung mit AngularJS unter Verwendung eines Eingabefelds. Ich werde es später erklären
HTML Quelltext
AngularJS-Code
Wie Sie im obigen Beispiel sehen können, AngularJS Anwendungen
ng-model
zu hören und sehen , was auf HTML - Elementen geschehen, vor allem aufinput
Felder. Wenn etwas passiert, tun Sie etwas. In unserem Fallng-model
ist an unsere Ansicht gebunden, unter Verwendung der Schnurrbartnotation{{}}
. Was auch immer in das Eingabefeld eingegeben wird, wird sofort auf dem Bildschirm angezeigt. Und das ist das Schöne an der Datenbindung, wenn AngularJS in seiner einfachsten Form verwendet wird.Hoffe das hilft.
Ein Arbeitsbeispiel finden Sie hier auf Codepen
quelle
AngularJs unterstützt die bidirektionale Datenbindung .
Dies bedeutet, dass Sie auf die Datenansicht -> Controller & Controller -> Ansicht zugreifen können
Zum Beispiel.
1)
O / P.
Sie können Daten in
ng-model
Like binden : -2)
Hier im obigen Beispiel wird die Eingabe des Benutzers im
<div>
Tag angezeigt.Wenn Sie Eingaben von HTML an den Controller binden möchten: -
3)
Wenn Sie hier einen Eingang
name
in der Steuerung verwenden möchten ,ng-model
bindet unsere Sichtweise und macht sie zum Ausdruck{{ }}
.ng-model
sind die Daten, die dem Benutzer in der Ansicht angezeigt werden und mit denen der Benutzer interagiert.So ist es einfach, Daten in AngularJs zu binden.
quelle
Angular.js erstellt einen Watcher für jedes Modell, das wir in der Ansicht erstellen. Jedes Mal, wenn ein Modell geändert wird, wird eine "ng-schmutzige" Klasse an das Modell angehängt, sodass der Beobachter alle Modelle mit der Klasse "ng-schmutzig" beobachtet und ihre Werte in der Steuerung aktualisiert und umgekehrt.
quelle
Datenbindung:
Was ist Datenbindung?
Immer wenn der Benutzer die Daten in der Ansicht ändert, erfolgt eine Aktualisierung dieser Änderung im Bereichsmodell und umgekehrt.
Wie ist es möglich?
Kurze Antwort: Mit Hilfe des Verdauungszyklus.
Beschreibung: Angular js setzt den Watcher auf das Scope-Modell, wodurch die Listener-Funktion ausgelöst wird, wenn sich das Modell ändert.
// Dom Update Code mit neuem Wert
});
Wann und wie wird die Watcher-Funktion aufgerufen?
Die Watcher-Funktion wird als Teil des Digest-Zyklus aufgerufen.
Der Digest-Zyklus wird automatisch als Teil von eckigen js aufgerufen, die in Direktiven / Diensten wie ng-model, ng-bind, $ timeout, ng-click und anderen integriert sind, mit denen Sie den Digest-Zyklus auslösen können.
Verdauungszyklusfunktion:
dh
$rootScope.$apply()
Hinweis: $ apply () ist gleich $ rootScope. $ Digest () bedeutet, dass die Dirty-Prüfung direkt vom Stamm oder oben oder vom übergeordneten Bereich bis zu allen untergeordneten $ Bereichen in der eckigen js-Anwendung beginnt.
Die oben genannten Funktionen funktionieren im IE des Browsers für die genannten Versionen auch nur, indem Sie sicherstellen, dass es sich bei Ihrer Anwendung um eine eckige js-Anwendung handelt. Dies bedeutet, dass Sie die im script-Tag angegebene Angularjs-Framework-Skriptdatei verwenden.
Vielen Dank.
quelle