AngularJS:$ observeメソッドと$ watchメソッドの違い


378

私は両方のことを知っているWatchersとはObserversで何かするとすぐに計算され$scopeAngularJSの変化。しかし、両者の違いは正確には理解できませんでした。

私の最初の理解は、関数が実行されたときに実行されるObserversHTML側の条件である角度式に対して計算Watchersされる$scope.$watch()ことです。私はきちんと考えていますか?


1
あなたの編集は役に立たず、少し不快です。実際に助けを求めてここに来る他の人々に配慮してください。
smalone 2016

@smaloneが変更されました。ありがとう、ごめんなさい!
Abilash

👍心配ありません。修正してくれてありがとう。
smalone 2016

回答:


608

$ observe()は、 Attributesオブジェクトのメソッドであるため、DOM属性の値の変化を観察または監視するためにのみ使用できます。内部ディレクティブでのみ使用/呼び出されます。補間を含むDOM属性(つまり、{{}})を観察または監視する必要がある場合は、$ observeを使用します。
例えば、attr1="Name: {{name}}"は、ディレクティブで:attrs.$observe('attr1', ...)
scope.$watch(attrs.attr1, ...){{}}のために試しても機能しません-が表示されますundefined。)それ以外の場合は、$ watchを使用します。

$ watch()はより複雑です。「式」を観察/監視できます。式は、関数または文字列のいずれかです。式が文字列の場合、それは関数に $ parse 'd(つまり、 Angular式として評価されます)されます。(ダイジェストサイクルごとに呼び出されるのはこの関数です。)文字列式に{{}}を含めることはできません。$ watchは Scopeオブジェクトのメソッドであるため、スコープオブジェクトにアクセスできる場所であればどこでも使用/呼び出しできます。

  • コントローラー-任意のコントローラー-ng-view、ng-controller、またはディレクティブコントローラーを介して作成されたもの
  • ディレクティブ内のリンク関数。これはスコープにもアクセスできるため

文字列はAngular式として評価されるため、$ watchはモデル/スコーププロパティを監視/監視するときによく使用されます。たとえば、attr1="myModel.some_prop"次に、コントローラまたはリンク関数で:scope.$watch('myModel.some_prop', ...)またはscope.$watch(attrs.attr1, ...)(またはscope.$watch(attrs['attr1'], ...))。
(試してみるとattrs.$observe('attr1')、文字列が表示されますがmyModel.some_prop、これはおそらく望んでいるものではありません。)

@PrimosKの回答のコメントで説明されているように、すべての$ observesと$ watchesはダイジェストサイクルごとにチェックされます

分離スコープを持つディレクティブは、より複雑です。'@'構文を使用する場合、補間を含むDOM属性(つまり、{{}})を$ observe または$ watchできます。($ watchで機能するのは、 '@'構文が補間を実行するためです。したがって、$ watchは{{}}のない文字列を参照します。)いつ使用するかを覚えやすくするために、この場合も$ observeします。

これをすべてテストするために、2つのディレクティブを定義するPlunkerを作成しました。1つ(d1)は新しいスコープを作成せず、もう1つ()はd2分離スコープを作成します。各ディレクティブには同じ6つの属性があります。各属性は、$ observe'dと$ watch'dの両方です。

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

コンソールログを見て、リンク関数の$ observeと$ watchの違いを確認します。次に、リンクをクリックして、クリックハンドラーによって行われたプロパティの変更によってトリガーされる$ observesおよび$ watchesを確認します。

リンク関数の実行時、{{}}を含む属性はまだ評価されていないことに注意してください(属性を調べようとすると、が表示されますundefined)。内挿された値を確認する唯一の方法は、$ observe(または '@'で分離スコープを使用している場合は$ watch)を使用することです。したがって、これらの属性の値の取得は非同期操作です。(そして、これが$ observe関数と$ watch関数が必要な理由です。)

時には、$ observeや$ watchは必要ありません。たとえば、属性に数値またはブール値(文字列ではない)が含まれている場合は、一度だけ評価しますattr1="22"。次に、たとえば、リンク関数で評価しますvar count = scope.$eval(attrs.attr1)。単なる定数文字列の場合– attr1="my string"attrs.attr1ディレクティブで使用するだけです($ eval()は不要)。

$ watch式に関するVojtaのgoogleグループの投稿も参照してください。


13
素晴らしい説明!+1
PrimosK 2013

4
正解です。なぜその代わりにng-src/ng-href使用attr.$observeするのか考えていscope.$watchますか?
okm 2013年

4
AngularJS教皇のために+1!Stackで最新のAngular問題に関する情報を検索するたびに、必然的に@MarkRajcokが承認した回答を読むことになります。
GFoley83 2013

1
素晴らしい投稿をありがとう。scope。$ eval(item)は本当に役に立ちます。itemがjson文字列の場合、jsonオブジェクトに変換されます。
bnguyen82 2013

5
@tamakisquare、@構文を使用するときにそれらは交換可能です。パフォーマンスの違いはないと思います(ただし、実際のソースコードは確認していません)。
Mark Rajcok 2013

25

私はあなたの質問を理解していれば右に、あなたがして、リスナーのコールバックを登録した場合の違いは何であるか求めている$watchか、あなたがそれを行う場合$observe

に登録されたコールバックは、実行$watch時に発生し$digestます。

に登録されて$observeいるコールバックは、補間を含む属性の値が変更されたときに呼び出されます(などattr="{{notJetInterpolated}}")。


ディレクティブ内では、非常によく似た方法で両方を使用できます。

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

または

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

3
実際、すべての変更は$digestフェーズで反映されるため、$observeコールバックがで呼び出されると想定しても安全$digestです。そして、$watchコールバックも呼び出されます$digestが、値が変更されるたびに呼び出されます。彼らはまったく同じ仕事をしていると思います:「式を見て、コールバックに値の変更を呼び出します」。キーワードの違いはおそらく、開発者を混乱させないための単なる構文上の砂糖です。
UmurKontacı2013

1
@fastreload、私はあなたのコメントに完全に同意します。
PrimosK 2013

@fastreload ...素晴らしい説明ありがとうございます。私が正しく理解していれば、オブザーバーは角度式用です。私は正しいですか?
Abilash 2013

@PrimosK:私の以前のコメントのためにあなたを追加します。
Abilash 2013

2
@Abilashオブザーバーは、式だけでなくdom属性を監視するためのものです。したがって、属性値を自分で変更すると、次のダイジェストサイクルに反映されます。
UmurKontacı2013

1

これはかなり明白だと思います:

  • $ observeは、ディレクティブのリンク機能で使用されます。
  • $ watchは、値の変化を監視するためにスコープで使用されます。

覚えておいてください:両方の関数には2つの引数があります、

$observe/$watch(value : string, callback : function);
  • value:常に監視される要素への文字列参照(スコープの変数の名前または監視されるディレクティブの属性の名前)
  • コールバック:フォームの実行される関数function (oldValue, newValue)

を作成しましたplunkerので、実際に両方の利用状況を把握できます。わかりやすくするために、カメレオンのアナロジーを使用しました。


2
その使用法についてはかなり明白です。しかし、なぜ問題だったのですか。マークはそれを美しくまとめました。
Abilash、2015年

3
paramsが切り替わる可能性があると思います-newValueを渡し、次にoldValueをattrs。$ observe()に渡すようです。。。
ブラスター

0

$ observeが$ watchと異なるのはなぜですか?

watchExpressionが評価され、各digest()サイクルで前の値と比較されます。watchExpression値に変更がある場合、watch関数が呼び出されます。

$ observeは、補間された値の監視に固有です。ディレクティブの属性値が補間されている場合、たとえばdir-attr="{{ scopeVar }}"、補間された値が設定されている場合(したがって、$ digestがすでに更新を行う必要があると判断した場合)に、observe関数が呼び出されます。基本的に、すでに補間のウォッチャーがあり、$ observe関数はそれを便乗させます。

compile.jsの $ observe&$ setを参照してください

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.