383 Stimmen

AngularJS: Unterschied zwischen den $observe und $watch Methoden

Ich weiß, dass sowohl Watchers als auch Observers in AngularJS sofort berechnet werden, wenn sich etwas in $scope ändert. Aber ich habe nicht verstanden, was genau der Unterschied zwischen den beiden ist.

Mein erstes Verständnis ist, dass Observers für Angular-Ausdrücke berechnet werden, die Bedingungen auf der HTML-Seite sind, während Watchers ausgeführt werden, wenn die $scope.$watch() Funktion aufgerufen wird. Denke ich richtig?

613voto

Mark Rajcok Punkte 356006

$observe() ist eine Methode des Attributes-Objekts und kann daher nur verwendet werden, um den Wert einer DOM-Attributänderung zu beobachten. Es wird nur innerhalb von Direktiven verwendet/aufgerufen. Verwenden Sie $observe, wenn Sie ein DOM-Attribut beobachten möchten, das Interpolation enthält (d.h. {{}}'s).
Zum Beispiel attr1="Name: {{name}}", dann in einer Direktive: attrs.$observe('attr1', ...).
(Wenn Sie scope.$watch(attrs.attr1, ...) versuchen, wird es aufgrund der {{}}s nicht funktionieren - Sie erhalten undefined. Verwenden Sie $watch für alles andere.

$watch() ist komplizierter. Es kann einen "Ausdruck" beobachten, wobei der Ausdruck entweder eine Funktion oder ein String sein kann. Wenn der Ausdruck ein String ist, wird er $parse'd (d.h. als Angular-Ausdruck ausgewertet) in eine Funktion. (Es ist diese Funktion, die in jedem Digest-Zyklus aufgerufen wird.) Der String-Ausdruck darf keine {{}}s enthalten. $watch ist eine Methode des Scope-Objekts, so dass es verwendet/aufgerufen werden kann, wo immer Sie Zugriff auf ein Scope-Objekt haben, also in

  • einem Controller - jedem Controller - einem, der über ng-view, ng-controller oder einen Direktivencontroller erstellt wurde
  • einer Verknüpfungsfunktion in einer Direktive, da diese ebenfalls Zugriff auf einen Scope hat

Weil Strings als Angular-Ausdrücke ausgewertet werden, wird $watch oft verwendet, wenn Sie ein Modell/Scope-Eigenschaft beobachten möchten. Zum Beispiel attr1="myModel.some_prop", dann in einem Controller oder Verknüpfungsfunktion: scope.$watch('myModel.some_prop', ...) oder scope.$watch(attrs.attr1, ...) (oder scope.$watch(attrs['attr1'], ...)).
(Wenn Sie attrs.$observe('attr1') versuchen, erhalten Sie den String myModel.some_prop, was wahrscheinlich nicht das ist, was Sie wollen.)

Wie in den Kommentaren zu @PrimosK's Antwort erläutert wurde, werden alle $observes und $watches bei jedem Digest-Zyklus überprüft.

Direktiven mit isolierten Scopes sind komplizierter. Wenn die '@'-Syntax verwendet wird, können Sie ein DOM-Attribut, das Interpolation enthält (d.h. {{}}s), $observe oder $watch. (Der Grund, warum es mit $watch funktioniert, liegt darin, dass die '@'-Syntax für uns die Interpolation durchführt, daher sieht $watch einen String ohne {{}}s.) Um es einfacher zu machen, sich zu merken, wann welches verwendet werden soll, schlage ich vor, $observe auch in diesem Fall zu verwenden.

Um all dies zu testen, habe ich einen Plunker geschrieben, der zwei Direktiven definiert. Eine (d1) erstellt keinen neuen Scope, die andere (d2) erstellt einen isolierten Scope. Jede Direktive hat dieselben sechs Attribute. Jedes Attribut wird sowohl $observe't als auch $watch't.

Schauen Sie sich die Konsolenausgabe an, um die Unterschiede zwischen $observe und $watch in der Verknüpfungsfunktion zu sehen. Klicken Sie dann auf den Link und sehen Sie, welche $observes und $watches durch die Änderungen der Eigenschaft ausgelöst werden, die durch den Klick-Handler vorgenommen wurden.

Beachten Sie, dass, wenn die Verknüpfungsfunktion ausgeführt wird, alle Attribute, die {{}}s enthalten, noch nicht ausgewertet werden (wenn Sie also versuchen, die Attribute zu überprüfen, erhalten Sie undefined). Der einzige Weg, um die interpolierten Werte zu sehen, ist die Verwendung von $observe (oder $watch bei Verwendung eines isolierten Scopes mit '@'). Das Abrufen der Werte dieser Attribute ist also ein asynchroner Vorgang. (Und das ist der Grund, warum wir die $observe- und $watch-Funktionen benötigen.)

Manchmal benötigen Sie kein $observe oder $watch. Zum Beispiel, wenn Ihr Attribut eine Zahl oder einen booleschen Wert enthält (keinen String), bewerten Sie es einfach einmal: attr1="22", dann in Ihrer Verknüpfungsfunktion zum Beispiel: var count = scope.$eval(attrs.attr1). Wenn es nur einen konstanten String enthält - attr1="mein String" - verwenden Sie einfach attrs.attr1 in Ihrer Direktive (kein Bedarf für $eval()).

Sehen Sie auch Vojtas Google-Group-Post über $watch-Ausdrücke.

26voto

PrimosK Punkte 13635

Wenn ich deine Frage richtig verstehe, fragst du nach dem Unterschied, ob du den Listener-Callback mit $watch oder mit $observe registrierst.

Der mit $watch registrierte Callback wird ausgeführt, wenn $digest ausgeführt wird.

Der mit $observe registrierte Callback wird aufgerufen, wenn sich die Werte von Attributen ändern, die Interpolation enthalten (z.B. attr="{{nochNichtInterpoliert}}").


In einer Direktive kannst du beide auf sehr ähnliche Weise verwenden:

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

oder

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

3voto

vdegenne Punkte 9972

Ich denke, das ist ziemlich offensichtlich:

  • $observe wird in der Verknüpfungsfunktion von Direktiven verwendet.
  • $watch wird auf den Scope angewendet, um Änderungen in seinen Werten zu überwachen.

Denken Sie daran: Beide Funktionen haben zwei Argumente,

$observe/$watch(value: string, callback: function);
  • value: ist immer ein String-Verweis auf das überwachte Element (der Name einer Variablen des Scopes oder der Name des Attributs der Direktive, das überwacht werden soll)
  • callback: die auszuführende Funktion in Form von function (oldValue, newValue)

Ich habe einen plunker erstellt, damit Sie tatsächlich einen Einblick in ihre Nutzung bekommen können. Ich habe die Chameleon-Analogie verwendet, um es einfacher zu veranschaulichen.

0voto

Niko Punkte 442

Warum ist $observe anders als $watch?

Der watchExpression wird bei jedem digest() Zyklus ausgewertet und mit dem vorherigen Wert verglichen. Wenn es eine Änderung im watchExpression-Wert gibt, wird die watch-Funktion aufgerufen.

$observe ist spezifisch für das Beobachten von interpolierten Werten. Wenn der Wert eines Direktivenattributs interpoliert ist, z. B. dir-attr="{{ scopeVar }}", wird die observe-Funktion nur aufgerufen, wenn der interpolierte Wert festgelegt ist (und daher wenn $digest bereits festgestellt hat, dass Aktualisierungen vorgenommen werden müssen). Im Grunde gibt es bereits einen Beobachter für die Interpolation, und die $observe-Funktion hängt davon ab.

Siehe $observe & $set in compile.js

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X