Saya mencoba memahami cara kerja Ember RunLoop dan apa yang membuatnya menarik. Saya telah melihat dokumentasinya , tetapi masih memiliki banyak pertanyaan tentangnya. Saya tertarik untuk memahami lebih baik bagaimana RunLoop bekerja sehingga saya dapat memilih metode yang sesuai dalam ruang namanya, ketika saya harus menunda eksekusi beberapa kode untuk lain waktu.
- Kapan Ember RunLoop dimulai. Apakah itu tergantung pada Router atau Views atau Controllers atau sesuatu yang lain?
- kira-kira berapa lama waktu yang dibutuhkan (saya tahu ini agak konyol untuk bertanya dan bergantung pada banyak hal tetapi saya mencari gambaran umum, atau mungkin jika ada waktu minimum atau maksimum yang mungkin diperlukan untuk runloop)
- Apakah RunLoop dijalankan setiap saat, atau hanya menunjukkan periode waktu dari awal hingga akhir eksekusi dan mungkin tidak berjalan untuk beberapa waktu.
- Jika tampilan dibuat dari dalam satu RunLoop, apakah dijamin bahwa semua kontennya akan masuk ke DOM pada saat loop berakhir?
Maafkan saya jika ini adalah pertanyaan yang sangat mendasar, saya pikir memahami ini akan membantu pemula seperti saya menggunakan Ember dengan lebih baik.
Jawaban:
Pembaruan 10/9/2013: Lihat visualisasi interaktif run loop ini: https://machty.s3.amazonaws.com/ember-run-loop-visual/index.html
Pembaruan 5/9/2013: semua konsep dasar di bawah ini masih mutakhir, tetapi sejak komit ini , implementasi Ember Run Loop telah dipisahkan menjadi pustaka terpisah yang disebut backburner.js , dengan beberapa perbedaan API yang sangat kecil.
Pertama, baca ini:
http://blog.sproutcore.com/the-run-loop-part-1/
http://blog.sproutcore.com/the-run-loop-part-2/
Mereka tidak 100% akurat untuk Ember, tetapi konsep inti dan motivasi di balik RunLoop umumnya masih berlaku untuk Ember; hanya beberapa detail penerapan yang berbeda. Tapi, untuk pertanyaan Anda:
Kapan Ember RunLoop dimulai. Apakah itu tergantung pada Router atau Views atau Controllers atau sesuatu yang lain?
Semua peristiwa pengguna dasar (misalnya peristiwa keyboard, peristiwa mouse, dll) akan menjalankan putaran proses. Ini menjamin bahwa perubahan apa pun yang dibuat pada properti terikat oleh peristiwa yang ditangkap (mouse / keyboard / timer / etc) sepenuhnya disebarkan ke seluruh sistem pengikatan data Ember sebelum mengembalikan kontrol kembali ke sistem. Jadi, menggerakkan mouse Anda, menekan sebuah tombol, mengklik tombol, dll., Semua meluncurkan run loop.
kira-kira berapa lama waktu yang dibutuhkan (saya tahu ini agak konyol untuk bertanya dan bergantung pada banyak hal tetapi saya mencari gambaran umum, atau mungkin jika ada waktu minimum atau maksimum yang mungkin diperlukan untuk runloop)
RunLoop tidak akan pernah melacak berapa lama waktu yang dibutuhkan untuk menyebarkan semua perubahan melalui sistem dan kemudian menghentikan RunLoop setelah mencapai batas waktu maksimum; bukan, runloop akan selalu berjalan sampai selesai, dan tidak akan berhenti sampai semua timer kadaluarsa telah dipanggil, binding disebarkan, dan mungkin mereka binding disebarkan, dan sebagainya. Jelas, semakin banyak perubahan yang perlu disebarluaskan dari satu peristiwa, semakin lama RunLoop akan selesai. Berikut adalah contoh (yang sangat tidak adil) tentang bagaimana RunLoop dapat macet dengan menyebarkan perubahan dibandingkan dengan kerangka kerja lain (Backbone) yang tidak memiliki run loop: http://jsfiddle.net/jashkenas/CGSd5/. Moral dari cerita ini: RunLoop sangat cepat untuk sebagian besar hal yang ingin Anda lakukan di Ember, dan di situlah letak sebagian besar kekuatan Ember, tetapi jika Anda ingin menganimasikan 30 lingkaran dengan Javascript pada 60 bingkai per detik, ada mungkin cara yang lebih baik untuk melakukannya daripada mengandalkan Ember's RunLoop.
Apakah RunLoop dijalankan setiap saat, atau hanya menunjukkan periode waktu dari awal hingga akhir eksekusi dan mungkin tidak berjalan untuk beberapa waktu.
Itu tidak dieksekusi setiap saat - itu harus mengembalikan kontrol kembali ke sistem di beberapa titik atau aplikasi Anda akan hang - ini berbeda dari, katakanlah, run loop pada server yang memiliki
while(true)
dan terus berjalan selama tak terbatas hingga server mendapat sinyal untuk dimatikan ... Ember RunLoop tidak memiliki seperti ituwhile(true)
tetapi hanya berputar sebagai respons terhadap peristiwa pengguna / pengatur waktu.Jika tampilan dibuat dari dalam satu RunLoop, apakah dijamin bahwa semua kontennya akan masuk ke DOM pada saat loop berakhir?
Mari kita lihat apakah kita bisa mengetahuinya. Salah satu perubahan besar dari SC ke Ember RunLoop adalah, alih-alih mengulang bolak-balik antara
invokeOnce
daninvokeLast
(yang Anda lihat di diagram di tautan pertama tentang SproutCore's RL), Ember memberi Anda daftar 'antrian' itu, di dalam putaran putaran, Anda dapat menjadwalkan tindakan (fungsi yang akan dipanggil selama putaran proses) dengan menentukan antrian mana tindakan tersebut (contoh dari sumber:)Ember.run.scheduleOnce('render', bindView, 'rerender');
.Jika Anda melihat
run_loop.js
dalam kode sumber, Anda melihatEmber.run.queues = ['sync', 'actions', 'destroy', 'timers'];
, namun jika Anda membuka debugger JavaScript di browser dalam aplikasi Ember dan mengevaluasiEmber.run.queues
, Anda mendapatkan daftar lengkap dari antrian:["sync", "actions", "render", "afterRender", "destroy", "timers"]
. Ember menjaga basis kode mereka cukup modular, dan mereka memungkinkan kode Anda, serta kodenya sendiri di bagian terpisah dari pustaka, untuk memasukkan lebih banyak antrian. Dalam hal ini, perpustakaan Ember Views menyisipkanrender
danafterRender
antrian, khususnya setelahactions
antrian. Saya akan membahas mengapa itu mungkin dalam beberapa detik. Pertama, algoritma RunLoop:Algoritme RunLoop kurang lebih sama seperti yang dijelaskan dalam artikel loop run SC di atas:
.begin()
dan.end()
, hanya di Ember Anda akan ingin menjalankan kode Anda di dalamnyaEmber.run
, yang secara internal akan memanggilbegin
danend
untuk Anda. (Hanya kode run loop internal dalam basis kode Ember yang masih menggunakanbegin
danend
, jadi Anda harus tetap menggunakannyaEmber.run
)end()
dipanggil, RunLoop kemudian memulai untuk menyebarkan setiap perubahan yang dibuat oleh potongan kode yang diteruskan keEmber.run
fungsi. Ini termasuk menyebarkan nilai properti terikat, menampilkan perubahan tampilan ke DOM, dll. Urutan di mana tindakan ini (mengikat, merender elemen DOM, dll) ditentukan olehEmber.run.queues
larik yang dijelaskan di atas:sync
. Ini akan menjalankan semua tindakan yang dijadwalkan ke dalamsync
antrian denganEmber.run
kode. Tindakan ini sendiri juga dapat menjadwalkan lebih banyak tindakan yang akan dilakukan selama RunLoop yang sama ini, dan RunLoop berhak untuk memastikan tindakan tersebut melakukan setiap tindakan hingga semua antrean dihapus. Cara melakukannya adalah, di akhir setiap antrean, RunLoop akan memeriksa semua antrean yang sebelumnya dihapus dan melihat apakah ada tindakan baru yang telah dijadwalkan. Jika demikian, itu harus dimulai di awal antrean paling awal dengan tindakan terjadwal yang tidak berkinerja baik dan menghapus antrean, terus melacak langkah-langkahnya dan memulai kembali bila perlu sampai semua antrean benar-benar kosong.Itulah inti dari algoritme. Begitulah cara data terikat disebarkan melalui aplikasi. Anda dapat mengharapkan bahwa setelah RunLoop berjalan hingga selesai, semua data terikat akan disebarkan sepenuhnya. Lalu, bagaimana dengan elemen DOM?
Urutan antrian, termasuk yang ditambahkan oleh pustaka Ember Views, penting di sini. Perhatikan itu
render
danafterRender
datang setelahsync
, danaction
. Thesync
antrian berisi semua tindakan untuk menyebarkan data yang terikat. (action
, setelah itu, hanya jarang digunakan di sumber Ember). Berdasarkan algoritma di atas, dijamin bahwa pada saat RunLoop mencapairender
antrian, semua data-binding telah selesai disinkronkan. Ini memang disengaja: Anda tidak ingin melakukan tugas mahal untuk merender elemen DOM sebelumnyamenyinkronkan data-binding, karena hal itu kemungkinan akan memerlukan rendering ulang elemen DOM dengan data yang diperbarui - jelas merupakan cara yang sangat tidak efisien dan rawan kesalahan untuk mengosongkan semua antrean RunLoop. Jadi, Ember dengan cerdas menyelesaikan semua pekerjaan pengikatan data yang dapat dilakukan sebelum merender elemen DOM dalamrender
antrean.Jadi, akhirnya, untuk menjawab pertanyaan Anda, ya, Anda dapat mengharapkan bahwa semua rendering DOM yang diperlukan akan terjadi pada saat
Ember.run
selesai. Berikut adalah jsFiddle untuk didemonstrasikan: http://jsfiddle.net/machty/6p6XJ/328/Hal lain yang perlu diketahui tentang RunLoop
Pengamat vs. Pengikatan
Penting untuk diperhatikan bahwa Observers dan Bindings, meskipun memiliki fungsi serupa untuk merespons perubahan dalam properti "watching", berperilaku sangat berbeda dalam konteks RunLoop. Binding propagation, seperti yang telah kita lihat, dijadwalkan ke
sync
antrian untuk akhirnya dieksekusi oleh RunLoop. Pengamat, di sisi lain, api segera ketika perubahan properti menyaksikan tanpa harus pertama dijadwalkan ke dalam antrian runloop. Jika Observer dan semua mengikat "watch" properti yang sama, pengamat akan selalu dipanggil 100% dari waktu sebelum pengikatan akan diperbarui.scheduleOnce
danEmber.run.once
Salah satu peningkatan efisiensi besar dalam template pembaruan otomatis Ember didasarkan pada fakta bahwa, berkat RunLoop, beberapa tindakan RunLoop yang identik dapat digabungkan ("dihapuskan", jika Anda mau) menjadi satu tindakan. Jika Anda melihat ke
run_loop.js
internal, Anda akan melihat fungsi yang memfasilitasi perilaku ini adalah fungsi terkaitscheduleOnce
danEm.run.once
. Perbedaan di antara keduanya tidak begitu penting seperti mengetahui keberadaannya, dan bagaimana mereka dapat membuang tindakan duplikat dalam antrean untuk mencegah banyak kalkulasi yang membengkak dan boros selama putaran proses.Bagaimana dengan pengatur waktu?
Meskipun 'timer' adalah salah satu antrean default yang tercantum di atas, Ember hanya membuat referensi ke antrean tersebut dalam kasus pengujian RunLoop mereka. Tampaknya antrean seperti itu akan digunakan pada hari-hari SproutCore berdasarkan beberapa deskripsi dari artikel di atas tentang pengatur waktu yang menjadi hal terakhir yang diaktifkan. Di Ember,
timers
antrian tidak digunakan. Sebaliknya, RunLoop dapat diputar olehsetTimeout
peristiwa yang dikelola secara internal (lihatinvokeLaterTimers
fungsinya), yang cukup cerdas untuk mengulang semua pengatur waktu yang ada, mengaktifkan semua pengatur waktu yang telah kedaluwarsa, menentukan pengatur waktu paling awal di masa mendatang, dan menyetel pengatur waktu internal.setTimeout
hanya untuk peristiwa itu, yang akan menjalankan RunLoop lagi saat diaktifkan. Pendekatan ini lebih efisien daripada meminta setiap pengatur waktu memanggil setTimeout dan membangunkannya sendiri, karena dalam kasus ini, hanya satu panggilan setTimeout yang perlu dibuat, dan RunLoop cukup cerdas untuk mengaktifkan semua pengatur waktu berbeda yang mungkin berbunyi pada saat yang sama waktu.Lebih lanjut debouncing dengan
sync
antrianBerikut cuplikan dari run loop, di tengah loop melalui semua antrian di run loop. Perhatikan kasus khusus untuk
sync
antrian: karenasync
merupakan antrian yang sangat volatil, di mana data disebarkan ke segala arah,Ember.beginPropertyChanges()
dipanggil untuk mencegah pengamat dipecat, diikuti dengan panggilan keEmber.endPropertyChanges
. Ini bijaksana: jika dalam proses membersihkansync
antrian, sangat mungkin bahwa properti pada suatu objek akan berubah beberapa kali sebelum bertumpu pada nilai akhirnya, dan Anda tidak ingin menyia-nyiakan sumber daya dengan segera menembakkan pengamat per setiap perubahan .Semoga ini membantu. Saya pasti harus belajar sedikit hanya untuk menulis hal ini, yang merupakan intinya.
sumber