AngularJS: Unterschied zwischen den Methoden $ watch und $ watch


378

Ich weiß, dass beide Watchersund Observersberechnet werden, sobald sich etwas $scopein AngularJS ändert. Aber ich konnte nicht verstehen, was genau der Unterschied zwischen den beiden ist.

Mein anfängliches Verständnis ist, dass Observersfür Winkelausdrücke berechnet werden, die Bedingungen auf der HTML-Seite sind, die Watchersausgeführt werden, wenn die $scope.$watch()Funktion ausgeführt wird. Denke ich richtig


1
Ihre Bearbeitung ist nicht hilfreich und etwas antagonisierend. Bitte nehmen Sie Rücksicht auf andere, die hierher kommen, um Hilfe zu erhalten.
— Smalone

@smalone geändert. Danke und Entschuldigung!
— Abilash

👍 Keine Sorge. Vielen Dank für die Korrektur.
— Smalone

Antworten:


608

$ watch () ist eine Methode für das Attributes- Objekt und kann daher nur zum Beobachten / Beobachten der Wertänderung eines DOM-Attributs verwendet werden. Es wird nur in Direktiven verwendet / aufgerufen. Verwenden Sie $ beobachten, wenn Sie ein DOM-Attribut beobachten / beobachten müssen, das Interpolation enthält (dh {{}}).
ZBattr1="Name: {{name}}"dann in einer Richtlinie :attrs.$observe('attr1', ...).
(Wenn Sie es versuchenscope.$watch(attrs.attr1, ...), funktioniert es aufgrund der {{}} s nicht - Sie erhaltenundefined.) Verwenden Sie $ watch für alles andere.

$ watch () ist komplizierter. Es kann einen "Ausdruck" beobachten / beobachten, wobei der Ausdruck entweder eine Funktion oder eine Zeichenfolge sein kann. Wenn der Ausdruck eine Zeichenfolge ist, wird $ parse 'd (dh als Winkelausdruck ausgewertet) in eine Funktion umgewandelt. (Diese Funktion wird bei jedem Digest-Zyklus aufgerufen.) Der Zeichenfolgenausdruck darf keine {{}} enthalten. $ watch ist eine Methode für das Scope- Objekt, sodass sie überall dort verwendet / aufgerufen werden kann, wo Sie Zugriff auf ein Scope-Objekt haben

  • Ein Controller - ein beliebiger Controller - einer, der über ng-view, ng-controller oder einen Direktiven-Controller erstellt wurde
  • eine Verknüpfungsfunktion in einer Direktive, da diese auch Zugriff auf einen Bereich hat

Da Zeichenfolgen als Winkelausdrücke ausgewertet werden, wird $ watch häufig verwendet, wenn Sie eine Modell- / Bereichseigenschaft beobachten / beobachten möchten. ZB attr1="myModel.some_prop"dann in einer Controller- oder Link-Funktion: scope.$watch('myModel.some_prop', ...)oder scope.$watch(attrs.attr1, ...)(oder scope.$watch(attrs['attr1'], ...)).
(Wenn Sie es versuchen, erhalten attrs.$observe('attr1')Sie die Zeichenfolge myModel.some_prop, die wahrscheinlich nicht Ihren Wünschen entspricht.)

Wie in den Kommentaren zur Antwort von @ PrimosK erläutert, werden alle $ Beobachtungen und $ Uhren in jedem Verdauungszyklus überprüft .

Richtlinien mit isolierten Bereichen sind komplizierter. Wenn die '@' - Syntax verwendet wird, können Sie ein DOM-Attribut, das Interpolation enthält (dh {{}}) , $ beobachten oder $ beobachten . (Der Grund, warum es mit $ watch funktioniert, ist, dass die '@' - Syntax die Interpolation für uns übernimmt. Daher sieht $ watch einen String ohne {{}}.) Um sich leichter zu merken, welcher wann verwendet werden soll, schlage ich vor, ihn zu verwenden $ auch für diesen Fall beachten.

Um all dies zu testen, habe ich einen Plunker geschrieben , der zwei Anweisungen definiert. One ( d1) erstellt keinen neuen Bereich, der andere ( d2) erstellt einen isolierten Bereich. Jede Direktive hat die gleichen sechs Attribute. Jedes Attribut wird sowohl $ beobachtet als auch $ beobachtet.

<div d1 attr1="{{prop1}}-test" attr2="prop2" attr3="33" attr4="'a_string'"
        attr5="a_string" attr6="{{1+aNumber}}"></div>

Sehen Sie sich das Konsolenprotokoll an, um die Unterschiede zwischen $ watch und $ watch in der Verknüpfungsfunktion zu sehen. Klicken Sie dann auf den Link und sehen Sie, welche $ Beobachtungen und $ Uhren durch die vom Klick-Handler vorgenommenen Eigenschaftsänderungen ausgelöst werden.

Beachten Sie, dass beim Ausführen der Verknüpfungsfunktion alle Attribute, die {{}} enthalten, noch nicht ausgewertet werden (wenn Sie also versuchen, die Attribute zu untersuchen, erhalten Sie undefined). Die einzige Möglichkeit, die interpolierten Werte anzuzeigen, ist die Verwendung von $ watch (oder $ watch, wenn ein isolierter Bereich mit '@' verwendet wird). Daher ist das Abrufen der Werte dieser Attribute eine asynchrone Operation. (Und deshalb brauchen wir die Funktionen $ watch und $ watch.)

Manchmal braucht man nicht $ beobachten oder $ beobachten. Wenn Ihr Attribut beispielsweise eine Zahl oder einen Booleschen Wert (keine Zeichenfolge) enthält, werten Sie ihn nur einmal aus: attr1="22"Dann beispielsweise in Ihrer Verknüpfungsfunktion : var count = scope.$eval(attrs.attr1). Wenn es sich nur um eine konstante Zeichenfolge handelt - attr1="my string"- verwenden Sie sie einfach attrs.attr1in Ihrer Direktive ($ eval () ist nicht erforderlich).

Siehe auch Vojtas Google-Gruppenbeitrag über $ watch-Ausdrücke.


13
Tolle Erklärung! +1
— PrimosK

4
Gute Antwort! Haben Sie Ahnung , warum ng-src/ng-hrefGebrauch attr.$observestatt scope.$watchdann?
— Ok,

4
+1 Für den AngularJS Papst! Jedes Mal, wenn ich in Stack nach Informationen zu meinem neuesten Angular-Problem suche, lese ich unweigerlich die von @MarkRajcok akzeptierte Antwort.
— GFoley83

1
Danke für einen tollen Beitrag. scope. $ eval (item) ist wirklich hilfreich. Wenn item eine JSON-Zeichenfolge ist, wird es in ein JSON-Objekt konvertiert.
— Bnguyen82

5
@tamakisquare, sie sind bei Verwendung der @Syntax austauschbar . Ich glaube, es gibt keinen Leistungsunterschied (aber ich habe mir den tatsächlichen Quellcode nicht angesehen).
— Mark Rajcok

25

Wenn ich Ihre Frage richtig verstehe, fragen Sie, was der Unterschied ist, wenn Sie einen Listener-Rückruf bei registrieren $watchoder wenn Sie dies tun $observe.

Callback registerd with $watchwird ausgelöst, wenn $digestes ausgeführt wird.

Rückruf registriert mit $observewird aufgerufen, wenn sich der Wert von Attributen ändert, die Interpolation enthalten (z attr="{{notJetInterpolated}}". B. ).


Innerhalb der Direktive können Sie beide auf sehr ähnliche Weise verwenden:

    attrs.$observe('attrYouWatch', function() {
         // body
    });

oder

    scope.$watch(attrs['attrYouWatch'], function() {
         // body
    });

3
Da sich jede Änderung in der $digestPhase widerspiegelt , kann davon ausgegangen werden, dass der $observeRückruf aufgerufen wird $digest. Ein $watchRückruf wird ebenfalls aufgerufen, $digestjedoch immer dann, wenn der Wert geändert wird. Ich denke, sie machen genau den gleichen Job: "Beobachten Sie den Ausdruck, rufen Sie die Wertänderungen zurück". Der Schlüsselwortunterschied ist möglicherweise nur syntaktischer Zucker, um den Entwickler nicht zu verwirren.
— Umur Kontacı

1
@fastreload, ich stimme deinem Kommentar voll und ganz zu. Schön geschrieben!
— PrimosK

@fastreload ... Danke für die wundervolle Erklärung. Wenn ich richtig verstanden habe, sind Beobachter für Winkelausdrücke. Habe ich recht?
— Abilash

@PrimosK: Füge dich für meinen vorherigen Kommentar hinzu.
— Abilash

2
@ Abilash-Beobachter dienen zum Beobachten von Dom-Attributen, nicht nur von Ausdrücken. Wenn Sie also den Attributwert selbst ändern, wird dies im nächsten Digest-Zyklus angezeigt.
— Umur Kontacı

1

Ich denke das ist ziemlich offensichtlich:

  • $ watch wird zur Verknüpfung von Direktiven verwendet.
  • $ watch wird im Bereich verwendet, um Änderungen seiner Werte zu beobachten.

Denken Sie daran : Beide Funktionen haben zwei Argumente:

$observe/$watch(value : string, callback : function);
  • value : ist immer eine Zeichenfolgenreferenz auf das überwachte Element (der Name der Variablen eines Bereichs oder der Name des zu überwachenden Attributs der Direktive)
  • Rückruf : Die auszuführende Funktion des Formularsfunction (oldValue, newValue)

Ich habe eine gemacht plunker, damit Sie tatsächlich einen Überblick über ihre Verwendung bekommen können. Ich habe die Chamäleon-Analogie verwendet, um das Bild einfacher zu machen.


2
Es ist ziemlich offensichtlich über seine Verwendung. Aber warum war die Frage. Mark hat es schön zusammengefasst.
— Abilash

3
Ich denke, die Parameter könnten umgeschaltet werden - es scheint, als würde newValue und dann oldValue an attrs übergeben. $ Observ (). . .
— Blaster

0

Warum unterscheidet sich $ beobachten von $ beobachten?

Die watchExpression wird ausgewertet und in jedem Digest () -Zyklus mit dem vorherigen Wert verglichen. Wenn sich der watchExpression-Wert ändert, wird die watch-Funktion aufgerufen.

$ watch ist spezifisch für das Suchen nach interpolierten Werten. Wenn der Attributwert einer Direktive interpoliert wird, z. B. dir-attr="{{ scopeVar }}"wird die Beobachtungsfunktion nur aufgerufen, wenn der interpolierte Wert festgelegt ist (und daher $ Digest bereits festgelegt hat, dass Aktualisierungen erforderlich sind). Grundsätzlich gibt es bereits einen Beobachter für die Interpolation, und die $ watch-Funktion huckepack davon.

Siehe $ watch & $ set in compile.js

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.