Saya harap saya tidak akan mempermalukan diri saya sendiri, tetapi saya mencoba memahami apa yang terjadi dalam dua baris kode tersebut:
document.body.innerHTML = 'something';
alert('something else');
Apa yang saya amati adalah peringatan itu muncul sebelum HTML diperbarui (atau mungkin sudah tetapi halaman belum di-refresh / dicat ulang / apa pun)
Lihat codepen ini untuk melihat apa yang saya maksud.
Harap dicatat bahwa bahkan menempatkan alert
di setTimeout(..., 0)
tidak membantu. Sepertinya perlu lebih banyak putaran acara untuk innerHTML
benar-benar memperbarui laman.
EDIT:
Saya lupa menyebutkan bahwa saya menggunakan Chrome dan tidak memeriksa browser lain. Sepertinya itu hanya terlihat di Chrome. Meski demikian saya masih tertarik mengapa hal itu bisa terjadi.
javascript
html
google-chrome
dom
masing-masing
sumber
sumber
Jawaban:
Menyetel innerHTML bersifat sinkron, seperti halnya sebagian besar perubahan yang dapat Anda lakukan pada DOM. Namun, merender halaman web adalah cerita yang berbeda.
(Ingat, DOM adalah singkatan dari "Document Object Model". Ini hanya "model", representasi data. Apa yang dilihat pengguna di layar mereka adalah gambaran bagaimana model itu seharusnya terlihat. Jadi, mengubah model tidak secara instan ubah gambar - perlu beberapa saat untuk memperbarui.)
Menjalankan JavaScript dan merender halaman web sebenarnya terjadi secara terpisah. Untuk meletakkannya menyederhanakan, pertama semua JavaScript pada halaman berjalan (dari loop acara - memeriksa video ini sangat baik untuk lebih detail) dan kemudian setelah itu browser merender perubahan apapun halaman web bagi pengguna untuk melihat. Inilah sebabnya mengapa "memblokir" adalah masalah besar - menjalankan kode yang intensif secara komputasi mencegah browser melewati langkah "jalankan JS" dan masuk ke langkah "render halaman", yang menyebabkan halaman macet atau tersendat.
Pipa Chrome terlihat seperti ini:
Seperti yang Anda lihat, semua JavaScript terjadi terlebih dahulu. Kemudian halaman diberi gaya, ditata, dicat, dan digabungkan - "render". Tidak semua pipeline ini akan mengeksekusi setiap frame. Itu tergantung pada elemen halaman apa yang diubah, jika ada, dan bagaimana mereka perlu dirender.
Catatan:
alert()
juga sinkron dan dijalankan selama langkah JavaScript, itulah sebabnya dialog peringatan muncul sebelum Anda melihat perubahan pada halaman web.Sekarang Anda mungkin bertanya "Tunggu, apa sebenarnya yang dijalankan dalam langkah 'JavaScript' di pipeline? Apakah semua kode saya berjalan 60 kali per detik?" Jawabannya adalah "tidak", dan ini kembali ke cara kerja loop event JS. Kode JS hanya berjalan jika ada di tumpukan - dari hal-hal seperti pendengar acara, waktu tunggu, apa pun. Lihat video sebelumnya (sungguh).
https://developers.google.com/web/fundamentals/performance/rendering/
sumber
Ya, ini sinkron, karena ini berfungsi (lanjutkan, ketik di konsol Anda):
Alasan Anda melihat peringatan sebelum Anda melihat halaman berubah adalah karena rendering browser membutuhkan lebih banyak waktu dan tidak secepat javascript Anda mengeksekusi baris demi baris.
sumber
text
dalam contoh saya) Itu akan menjawab pertanyaan Anda apakah itu sinkron. Rendering browser vs. eksekusi Javascript adalah apel dan jeruk :)The
innerHTML
properti yang sebenarnya tidak diperbarui serentak, tetapi redraw visual yang perubahan ini menyebabkan terjadi asynchronous.Rendering visual DOM tidak sinkron di Chrome dan tidak akan terjadi hingga tumpukan fungsi JavaScript saat ini dibersihkan dan browser bebas untuk menerima acara baru. Browser lain mungkin menggunakan utas terpisah untuk menangani kode JavaScript dan rendering browser, atau mereka mungkin membiarkan beberapa peristiwa mendapatkan prioritas sementara peringatan menghentikan pelaksanaan acara lain.
Anda dapat melihat ini dengan dua cara:
Jika Anda menambahkan
for(var i=0; i<1000000; i++) { }
sebelum peringatan Anda, Anda telah memberi browser banyak waktu untuk menggambar ulang, tetapi belum, karena tumpukan fungsi belum dihapus (add
masih berjalan).Jika Anda menunda
alert
melalui asinkronsetTimeout(function() { alert('random'); }, 1)
, proses penggambaran ulang akan melanjutkan fungsi yang ditunda oleh setTimeout.0
, mungkin karena Chrome memberikan prioritas antrean acara ke0
waktu tunggu sebelum acara lain (atau setidaknya sebelum menggambar ulang acara).sumber
setTimeout(func, 1)
tidak berfungsi setiap waktu, periksa video ini: youtu.be/r8caVE_a5KQ