Apa perbedaan antara $ evalAsync dan $ timeout di AngularJS?

180

Saya telah menggunakan AngularJS untuk sementara waktu sekarang, dan telah menemukan kebutuhan untuk menggunakan $ timeout sesekali (Sepertinya biasanya untuk init plugin jQuery).

Baru-baru ini, saya telah mencoba untuk mendapatkan pemahaman yang lebih baik dan lebih mendalam tentang siklus intisari, dan saya menemukan fungsi $ evalAsync .

Sepertinya fungsi itu menghasilkan hasil yang serupa $timeout, hanya saja Anda tidak memberinya penundaan. Setiap kali saya telah menggunakannya $timeoutdengan keterlambatan 0, jadi sekarang saya bertanya-tanya apakah saya seharusnya menggunakannya $evalAsync.

Apakah ada perbedaan mendasar antara keduanya? Kasing apa yang akan Anda gunakan satu di atas yang lain? Saya ingin mendapatkan perasaan yang lebih baik tentang kapan harus menggunakan yang mana.

dnc253
sumber

Jawaban:

263

Saya baru-baru ini pada dasarnya menjawab pertanyaan ini di sini: https://stackoverflow.com/a/17239084/215945 (Jawaban itu menghubungkan ke beberapa pertukaran github dengan Misko.)

Untuk meringkas:

  • jika kode di-antri menggunakan $ evalAsync dari suatu direktif , kode tersebut harus dijalankan setelah DOM telah dimanipulasi oleh Angular, tetapi sebelum browser membuat
  • jika kode di-antri menggunakan $ evalAsync dari controller , kode harus dijalankan sebelum DOM dimanipulasi oleh Angular (dan sebelum browser merender) - jarang Anda menginginkan ini
  • jika kode di-antri menggunakan $ timeout , kode harus dijalankan setelah DOM dimanipulasi oleh Angular, dan setelah browser merender (yang dapat menyebabkan flicker dalam beberapa kasus)
Mark Rajcok
sumber
15
Terima kasih atas penjelasannya. Satu hal yang saya tidak yakin saya mengerti. Mengapa ada bedanya jika Anda memanggil $ evalAsync dari controller atau directive? AsyncQueue tidak tahu apakah itu terdaftar dari pengontrol atau arahan, itu hanya mengantri pada ruang lingkup saat ini. Apakah itu ada hubungannya dengan ketika hal-hal berjalan di pengontrol vs pengontrol? Saya hanya ingin memahami bagian itu.
dnc253
@ dnc253, saya belum melihat kode Angular, jadi saya tidak tahu jawaban untuk pertanyaan (baik) Anda. Semoga orang lain bisa berkomentar.
Mark Rajcok
15
Apakah "dari arahan" berarti "dari fungsi penautan arahan"? Atau apakah itu benar dari perilaku ketika dijalankan dari metode penghubung atau pengarah dari arahan?
SimplGy
5
ya, benar-benar tidak jelas apa yang dimaksud "dari arahan" dan "dari pengontrol" di sini
thorn
1
@MarkRajcok, bisakah Anda menjelaskan di sini: jika kode diantrikan menggunakan $ evalAsync dari arahan, itu harus dijalankan setelah DOM telah dimanipulasi oleh Angular - haruskah dijalankan setelah DOM dimanipulasi oleh arahan ini, atau oleh arahan lain?
Max Koretskyi
59

Untuk mereka yang membangun aplikasi yang kompleks, perlu diketahui bahwa ada dampak kinerja pada pilihan Anda. Saya juga ingin melengkapi jawaban Mark dengan rincian teknis lebih lanjut:

  • $ timeout (callback) akan menunggu siklus digest saat ini dilakukan (mis. perbarui semua model dan DOM), kemudian akan menjalankan callback - berpotensi memengaruhi model sudut - kemudian meluncurkan penuh $applypada lingkup $ root, dan redigest segala sesuatu.

  • $ evalAsync (callback) , di sisi lain, akan menambahkan callback ke siklus saat ini, atau selanjutnya, digest. Yang berarti jika Anda berada dalam siklus intisari (misalnya dalam fungsi yang dipanggil dari beberapa ng-clickarahan), ini tidak akan menunggu apa pun, kode akan segera dieksekusi. Jika Anda berada dalam panggilan asinkron, misalnya a setTimeout, siklus intisari baru ( $apply) akan dipicu.

Jadi dalam hal kinerja selalu lebih baik untuk memanggil $evalAsync, kecuali penting bagi Anda bahwa tampilan adalah yang terbaru sebelum mengeksekusi kode Anda, misalnya jika Anda memerlukan akses ke beberapa atribut DOm seperti lebar elemen dan sejenisnya.

Jika Anda ingin detail lebih lanjut tentang perbedaan antara $ timeout, $ evalAsync, $ digest, $ apply, saya mengundang Anda untuk membaca jawaban saya pada pertanyaan lain: https://stackoverflow.com/a/23102223/1501926

Pastikan juga untuk membaca dokumentasi :

$ EvalAsync tidak memberikan jaminan kapan ekspresi akan dieksekusi, hanya itu:

  • itu akan dieksekusi setelah fungsi yang menjadwalkan evaluasi (sebaiknya sebelum rendering DOM).
  • setidaknya satu siklus $ digest akan dilakukan setelah eksekusi ekspresi.

Catatan: jika fungsi ini disebut di luar siklus $ digest, siklus $ digest baru akan dijadwalkan . Namun, disarankan untuk selalu memanggil kode yang mengubah model dari dalam panggilan $ apply. Itu termasuk kode yang dievaluasi melalui $ evalAsync.

floribon
sumber
Bisakah Anda jelaskan mengapa $ timeout diperlukan jika saya perlu mengakses beberapa atribut DOM. Katakanlah jika saya memiliki <table width = "{{x}}"> Tidak menonton fungsi ng-bind memperbarui atribut dom di memori, saya mengerti itu tidak akan memiliki kesempatan untuk mengecat ulang tampilan sampai siklus digest keluar.
Sridhar Chidurala
2
@SridharChidurala karena DOM ("HTML") diperbarui selama siklus digest, Anda harus menunggu sampai selesai sebelum Anda dapat membaca mofifikasi. Namun ini tidak disarankan oleh Angular, Anda harus membaca xdari ruang lingkup Anda secara langsung daripada dari DOM, sehingga Anda tidak perlu menunggu apa pun. Selain itu, Anda sebaiknya menggunakan ng-styledengan css daripada widthproperti usang . Jika Anda membutuhkan bantuan lebih lanjut, silakan buka pertanyaan baru di StackOverflow.
floribon