AngularJS: $ observe ve $ watch yöntemleri arasındaki fark


378

Ben her ikisi de biliyorum Watchersve AngularJS değişiklikleri bir Observersşey en kısa sürede hesaplanır $scope. Ancak ikisi arasındaki farkın tam olarak ne olduğunu anlayamadım.

İlk anlayışım, ObserversHTML Watchersyürütüldüğünde $scope.$watch()işlev yürütüldüğünde yürütüldüğü gibi koşullar olan açısal ifadeler için hesaplanmasıdır . Doğru düşünüyor muyum?


1
Düzenlemeniz faydalı değil ve biraz antagonize ediyor. Lütfen buraya gerçek yardım için gelenleri düşünün.
smalone

@smalone değişti. Teşekkürler ve üzgünüm!
Abilash

Wor Endişelenme. Düzelttiğiniz için teşekkürler.
smalone

Yanıtlar:


608

$ observe () , Nitelikler nesnesindekibir yöntemdirve bu nedenle, yalnızca bir DOM özelliğinin değer değişikliğini gözlemlemek / izlemek için kullanılabilir. Yalnızca iç yönergelerde kullanılır / çağrılır. Enterpolasyon içeren bir DOM özelliğini (yani, {{}} 's) gözlemlemeniz / izlemeniz gerektiğinde $ gözlemle komutunu kullanın.
Örneğin,attr1="Name: {{name}}"daha sonra bir yönergede:attrs.$observe('attr1', ...).
(Eğer denersenizscope.$watch(attrs.attr1, ...){{}} s nedeniyle çalışmaz - elde edersinizundefined.) Diğer her şey için $ watch kullanın.

$ watch () daha karmaşıktır. İfadenin bir işlev veya dize olabileceği bir "ifadeyi" gözlemleyebilir / izleyebilir. İfade bir dize ise,bir işleve $ parse 'd (yani, Açısal ifade olarak değerlendirilir). (Bu, her özet döngüsü olarak adlandırılan işlevdir.) Dize ifadesi {{}} 'ler içeremez. $ watch, Scope nesnesindekibir yöntemdir, bu nedenle kapsam nesnesine erişiminiz olan her yerde kullanılabilir / çağrılabilir.

  • bir kontrolör - herhangi bir kontrolör - ng-view, ng-kontrolör veya bir direktif kontrolörü ile oluşturulan
  • bir direktifte bir bağlama fonksiyonu, çünkü bunun bir kapsama da erişimi vardır

Dizeler Açısal ifadeler olarak değerlendirildiğinden, $ watch genellikle bir model / scope özelliğini gözlemlemek / izlemek istediğinizde kullanılır. Örneğin, attr1="myModel.some_prop"bir denetleyici veya bağlantı işlevinde: scope.$watch('myModel.some_prop', ...)veya scope.$watch(attrs.attr1, ...)(veya scope.$watch(attrs['attr1'], ...)).
(Eğer denerseniz , muhtemelen istediğiniz gibi olmayan bir attrs.$observe('attr1')dize alırsınız myModel.some_prop.)

@ PrimosK'un cevabı hakkındaki yorumlarda tartışıldığı gibi, tüm $ gözlemleri ve $ saatler her sindirim döngüsünde kontrol edilir .

İzole kapsamları olan yönergeler daha karmaşıktır. '@' Sözdizimi kullanılırsa, enterpolasyon içeren bir DOM özniteliğini (örneğin, {{}}) gözlemleyebilir veya $ izleyebilirsiniz . ($ Watch ile çalışmasının nedeni '@' sözdiziminin bizim için enterpolasyon yapmasıdır , bu nedenle $ watch {{}} 'lar olmadan bir dize görür.) Hangisinin ne zaman kullanılacağını hatırlamayı kolaylaştırmak için $ da bu dava için gözlemlemek.

Tüm bunların test edilmesine yardımcı olmak için iki direktif tanımlayan bir Plunker yazdım . Bir ( d1) yeni bir kapsam oluşturmaz, diğeri ( d2) ayrı bir kapsam oluşturur. Her direktif aynı altı özelliğe sahiptir. Her özellik $ gözlemlenir ve $ izlenir.

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

Bağlama işlevinde $ observe ve $ watch arasındaki farkları görmek için konsol günlüğüne bakın. Ardından bağlantıyı tıklayın ve tıklama işleyicisi tarafından yapılan özellik değişiklikleri tarafından hangi $ gözlemlerinin ve $ saatlerinin tetiklendiğini görün.

Bağlantı işlevi çalıştığında, {{}} 'ları içeren özniteliklerin henüz değerlendirilmediğine dikkat edin (bu nedenle öznitelikleri incelemeye çalışırsanız, elde edersiniz undefined). Enterpolasyonlu değerleri görmenin tek yolu $ observe (veya '@' ile bir izolat kapsamı kullanıyorsa $ watch) kullanmaktır. Bu nedenle, bu özniteliklerin değerlerini almak eşzamansız bir işlemdir. (Bu yüzden $ gözlemleme ve $ izleme işlevlerine ihtiyacımız var.)

Bazen $ gözlem veya $ izlemek gerekmez. Senin özelliğin bir sayı veya boolean (bir dize) içeriyorsa Örneğin, sadece bir kez değerlendirmek: attr1="22", sonra bağlama işlevi, sözgelimi: var count = scope.$eval(attrs.attr1). Sadece sabit bir dize ise - attr1="my string"- o zaman sadece attrs.attr1direktifinizde kullanın ($ eval () gerekmez).

Ayrıca $ watch ifadeleri hakkında Vojta'nın google grup yayınına bakın .


13
Harika bir açıklama! +1
PrimosK

4
Mükemmel cevap! Neden o zaman ng-src/ng-hrefkullanmak attr.$observeyerine bir fikrin var scope.$watchmı?
okm

4
+1 AngularJS Papa için! Stack'i en son Açısal sorunum hakkında bazı bilgiler aradığımda, kaçınılmaz olarak @MarkRajcok kabul edilen cevabı okudum.
GFoley83

1
Harika bir gönderi için teşekkürler. $ eval (item) gerçekten yardımcı olur. Öğe bir json dizgiyse, bir json nesnesine dönüştürülür.
bnguyen82

5
@tamakisquare, @sözdizimi kullanılırken değiştirilebilir . Performans farkı olmadığını düşünüyorum (ancak gerçek kaynak koduna bakmadım).
Mark Rajcok

25

Sorunuzu doğru anlarsam, dinleyici geri aramasını kaydettirirseniz $watchveya ile yaparsanız, farkın ne olduğunu soruyorsunuz $observe.

İle Geri arama registerd $watchne zaman ateş $digestyürütülür.

Kayıtlı geri arama $observe, enterpolasyon içeren özniteliklerin değer değişiklikleri (örneğin attr="{{notJetInterpolated}}") olduğunda çağrılır .


Direktifin içinde her ikisini de çok benzer bir şekilde kullanabilirsiniz:

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

veya

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

3
Aslında, her değişiklik $digestaşamada yansıtıldığından , $observegeri aramanın çağrılacağını varsaymak güvenlidir $digest. Ve $watchgeri arama da çağrılır, $digestancak değer her değiştiğinde. Aynı işi yaptıklarını düşünüyorum: "ifadeyi izle, geri arama değer değişiklikleri". Anahtar kelime farkı muhtemelen geliştiriciyi karıştırmamak için sözdizimsel şekerdir.
Umur Kontacı

1
@ fastreload, yorumunuza tamamen katılıyorum .. Güzel yazılmış!
PrimosK

@fastreload ... Harika açıklama için teşekkürler. Doğru anladıysam Gözlemciler Açısal İfadeler içindir. Haklı mıyım?
Abilash

@PrimosK: önceki yorumum için seni ekliyorum.
Abilash

2
@Abilash gözlemcileri sadece ifadeleri değil dom özelliklerini de izlemek içindir. Dolayısıyla, öznitelik değerini kendiniz değiştirirseniz, bir sonraki özet döngüsüne yansıtılır.
Umur Kontacı

1

Bunun oldukça açık olduğunu düşünüyorum:

  • Direktiflerin bağlantı fonksiyonunda $ observe kullanılır.
  • $ watch, değerlerinde herhangi bir değişikliği izlemek için kapsamda kullanılır.

Unutmayın : her iki işlevin de iki argümanı vardır,

$observe/$watch(value : string, callback : function);
  • value : her zaman izlenen öğeye bir dize başvurusudur (bir kapsam değişkeninin adı veya izlenecek yönerge özelliğinin adı)
  • geri arama : formun yürütülecek işlevifunction (oldValue, newValue)

Bir yaptım plunker, böylece aslında her ikisinin de kullanımını kavrayabilirsiniz. Resim yapmayı kolaylaştırmak için bukalemun benzetmesini kullandım.


2
Kullanımları hakkında oldukça açıktır. Ama soru neydi? Mark güzelce özetledi.
Abilash

3
Bence paramlar değiştirilmiş olabilir - newValue, sonra oldValue attrs. $ Observe (). . .
Blaster

0

$ Gözlemlemek neden $ watch'dan farklı?

WatchExpression değerlendirilir ve her özet () döngüsünde önceki değerle karşılaştırılır; watchExpression değerinde bir değişiklik varsa, saat işlevi çağrılır.

$ observe, enterpolasyonlu değerleri izlemeye özgüdür. Bir direktifin öznitelik değeri enterpole edilirse, örneğin dir-attr="{{ scopeVar }}", gözlemleme fonksiyonu yalnızca enterpolasyonlu değer ayarlandığında (ve bu nedenle $ digest zaten belirlenmiş güncellemelerin yapılması gerektiğinde) çağrılır. Temel olarak enterpolasyon için zaten bir izleyici var ve $ gözlemleme fonksiyonu bindirmelerden kurtuluyor.

Compile.js dosyasında $ observe & $ set ifadesine bakın

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.