AngularJS: Perbedaan antara metode $ observ dan $ watch

378

Saya tahu bahwa keduanya Watchersdan Observersdihitung segera setelah sesuatu dalam $scopeperubahan di AngularJS. Tapi tidak bisa mengerti apa sebenarnya perbedaan antara keduanya.

Pemahaman awal saya adalah yang Observersdihitung untuk ekspresi sudut yang merupakan kondisi di sisi HTML tempat Watchersdieksekusi ketika $scope.$watch()fungsi dieksekusi. Apakah saya berpikir dengan benar?

Abilash
sumber
1
Hasil edit Anda tidak membantu dan agak memusuhi. Harap perhatikan orang lain yang datang ke sini untuk bantuan aktual.
smalone
@smalone berubah. Terima kasih dan maaf!
Abilash
👍 Jangan khawatir. Terima kasih telah memperbaikinya.
smalone

Jawaban:

608

$ observ () adalah metode padaobjek Attributes , dan karenanya, hanya dapat digunakan untuk mengamati / menonton perubahan nilai atribut DOM. Ini hanya digunakan / disebut arahan dalam. Gunakan $ mengamati ketika Anda perlu mengamati / menonton atribut DOM yang berisi interpolasi (yaitu, {{}} 's).
Misalnya,attr1="Name: {{name}}"maka dalam Instruksi:attrs.$observe('attr1', ...).
(Jika Anda mencobanyascope.$watch(attrs.attr1, ...)tidak akan berhasil karena {{}} s - Anda akan mendapatkannyaundefined.) Gunakan $ watch untuk yang lainnya.

$ watch () lebih rumit. Ia dapat mengamati / menonton "ekspresi", di mana ekspresi dapat berupa fungsi atau string. Jika ekspresi adalah string, itu adalah $ parse 'd (yaitu, dievaluasi sebagai ekspresi Angular ) ke dalam suatu fungsi. (Fungsi inilah yang disebut setiap siklus intisari.) Ekspresi string tidak dapat berisi {{}}. $ watch adalah metode padaobjek Lingkup , sehingga dapat digunakan / dipanggil di mana pun Anda memiliki akses ke objek lingkup, maka dalam

  • controller - controller apa saja - yang dibuat melalui ng-view, ng-controller, atau directive controller
  • fungsi penautan dalam arahan, karena ini juga memiliki akses ke ruang lingkup

Karena string dievaluasi sebagai ekspresi Angular, $ watch sering digunakan ketika Anda ingin mengamati / menonton properti model / lingkup. Misalnya,, attr1="myModel.some_prop"lalu dalam fungsi pengontrol atau tautan: scope.$watch('myModel.some_prop', ...)atau scope.$watch(attrs.attr1, ...)(atau scope.$watch(attrs['attr1'], ...)).
(Jika Anda mencoba, attrs.$observe('attr1')Anda akan mendapatkan string myModel.some_prop, yang mungkin bukan yang Anda inginkan.)

Seperti dibahas dalam komentar pada jawaban @ PrimosK, semua $ mengamati dan $ jam diperiksa setiap siklus intisari .

Arahan dengan lingkup isolasi lebih rumit. Jika sintaks '@' digunakan, Anda dapat $ mengamati atau $ menonton atribut DOM yang berisi interpolasi (yaitu, {{}}). (Alasan kerjanya dengan $ watch adalah karena sintaks '@' melakukan interpolasi untuk kita, maka $ watch melihat string tanpa {{}} 's.) Untuk membuatnya lebih mudah untuk mengingat yang harus digunakan saat, saya sarankan menggunakan $ perhatikan untuk kasus ini juga.

Untuk membantu menguji semua ini, saya menulis sebuah Plunker yang mendefinisikan dua arahan. Satu ( d1) tidak membuat ruang lingkup baru, yang lain ( d2) menciptakan ruang lingkup terisolasi. Setiap arahan memiliki enam atribut yang sama. Setiap atribut adalah $ observ'd dan $ watch'ed.

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

Lihatlah log konsol untuk melihat perbedaan antara $ observ dan $ watch dalam fungsi penautan. Kemudian klik tautan dan lihat $ mengamati dan $ jam tangan mana yang dipicu oleh perubahan properti yang dilakukan oleh pengendali klik.

Perhatikan bahwa ketika fungsi tautan berjalan, atribut apa pun yang mengandung {{}} belum dievaluasi (jadi jika Anda mencoba memeriksa atribut, Anda akan mendapatkannya undefined). Satu-satunya cara untuk melihat nilai-nilai yang diinterpolasi adalah dengan menggunakan $ observ (atau $ watch jika menggunakan lingkup isolat dengan '@'). Oleh karena itu, mendapatkan nilai atribut ini adalah operasi yang tidak sinkron . (Dan inilah mengapa kita membutuhkan fungsi $ mengamati dan $ menonton.)

Terkadang Anda tidak perlu $ mengamati atau $ menonton. Misalnya, jika atribut Anda berisi nomor atau boolean (bukan string), hanya mengevaluasi sekali: attr1="22", maka dalam, katakanlah, fungsi menghubungkan Anda: var count = scope.$eval(attrs.attr1). Jika itu hanya string konstan - attr1="my string"- maka gunakan saja attrs.attr1direktif Anda (tidak perlu $ eval ()).

Lihat juga posting grup google Vojta tentang $ watch expressions.

Mark Rajcok
sumber
13
Penjelasan hebat! +1
PrimosK
4
Jawaban bagus! Apakah Anda tahu mengapa ng-src/ng-hrefpenggunaan attr.$observebukan scope.$watchitu?
okm
4
+1 Untuk Paus AngularJS! Setiap kali saya mencari Stack untuk beberapa info tentang masalah Angular terbaru saya, akhirnya saya membaca @MarkRajcok jawaban yang diterima.
GFoley83
1
Terima kasih untuk kiriman yang bagus. ruang lingkup. $ eval (item) sangat membantu. Jika item adalah string json, itu dikonversi ke objek json.
bnguyen82
5
@takakisquare, mereka dapat dipertukarkan saat menggunakan @sintaks. Saya percaya tidak ada perbedaan kinerja (tapi saya belum melihat kode sumber yang sebenarnya).
Mark Rajcok
25

Jika saya mengerti pertanyaan Anda dengan benar, Anda bertanya apa bedanya jika Anda mendaftar dengan panggilan balik pendengar $watchatau jika Anda melakukannya $observe.

Register callback dengan $watchdipecat ketika $digestdieksekusi.

Callback terdaftar dengan $observedipanggil ketika nilai perubahan atribut yang mengandung interpolasi (misalnya attr="{{notJetInterpolated}}").


Di dalam arahan Anda dapat menggunakan keduanya dengan cara yang sangat mirip:

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

atau

    scope.$watch(attrs['attrYouWatch'], function() {
         // body
    });
PrimosK
sumber
3
Sebenarnya, karena setiap perubahan tercermin dalam $digestfase, aman untuk mengasumsikan bahwa $observepanggilan balik akan dipanggil $digest. Dan $watchpanggilan balik juga akan dipanggil $digesttetapi kapan pun nilainya berubah. Saya pikir mereka melakukan pekerjaan yang sama persis: "perhatikan ekspresi, panggil panggilan balik nilainya berubah". Perbedaan kata kunci mungkin hanya gula sintaksis karena tidak membingungkan pengembang.
Umur Kontacı
1
@ fastreload, saya setuju dengan komentar Anda .. Ditulis dengan baik!
PrimosK
@ fastreload ... Terima kasih atas penjelasannya. Jika saya mengerti dengan benar, Pengamat adalah untuk Ekspresi Angular. Apakah saya benar?
Abilash
@RimosK: menambahkan Anda untuk komentar saya sebelumnya.
Abilash
2
Pengamat @Abilash adalah untuk menonton atribut dom, bukan hanya ekspresi. Jadi jika Anda mengubah nilai atribut sendiri, itu akan tercermin dalam siklus intisari berikutnya.
Umur Kontacı
1

Saya pikir ini cukup jelas:

  • $ mengamati digunakan dalam menghubungkan fungsi arahan.
  • $ watch digunakan pada scope untuk melihat setiap perubahan nilainya.

Perlu diingat : kedua fungsi memiliki dua argumen,

$observe/$watch(value : string, callback : function);
  • value : selalu berupa referensi string ke elemen yang ditonton (nama variabel lingkup atau nama atribut direktif yang akan ditonton)
  • callback : fungsi yang akan dieksekusi dari formulirfunction (oldValue, newValue)

Saya telah membuat plunker, jadi Anda benar-benar bisa memahami pemanfaatan keduanya. Saya telah menggunakan analogi Chameleon untuk membuatnya lebih mudah digambarkan.

vdegenne
sumber
2
Cukup jelas tentang penggunaannya. Tapi mengapa pertanyaannya. Markus menyimpulkannya dengan indah.
Abilash
3
Saya pikir params mungkin diaktifkan - tampaknya melewati newValue, lalu oldValue ke attrs. $ Mengamati (). . .
blaster
0

Mengapa $ mengamati berbeda dari $ menonton?

WatchExpression dievaluasi dan dibandingkan dengan nilai sebelumnya setiap siklus digest (), jika ada perubahan dalam nilai watchExpression, fungsi jam disebut.

$ observ khusus untuk mengamati nilai yang diinterpolasi. Jika nilai atribut direktif diinterpolasi, misalnya dir-attr="{{ scopeVar }}", fungsi mengamati hanya akan dipanggil ketika nilai interpolasi diatur (dan karena itu ketika $ digest telah menentukan pembaruan harus dilakukan). Pada dasarnya sudah ada pengamat interpolasi, dan fungsi $ mengamati dukung itu.

Lihat $ mengamati & $ set di compile.js

Niko
sumber