İnnerHTML zaman uyumsuz mu?


103

Umarım kendimi aptal yerine koymam ama bu iki satır kodda neler olduğunu anlamaya çalışıyorum:

document.body.innerHTML = 'something';
alert('something else');

Gözlemlediğim şey, uyarının HTML güncellenmeden önce gösterilmesidir (veya belki de olmuştur, ancak sayfa yenilenmemiş / yeniden boyanmamıştır / her neyse)

Ne demek istediğimi görmek için bu codepen'e bakın.

Hatta koyarak not edin alertde setTimeout(..., 0)yardım etmez. Görünüşe göre innerHTMLsayfayı gerçekten güncellemek için daha fazla olay döngüsü gerekiyor.

DÜZENLE:

Chrome kullandığımı söylemeyi unuttum ve diğer tarayıcıları kontrol etmedim. Görünüşe göre yalnızca Chrome'da görünüyor. Yine de bunun neden olduğunu hala merak ediyorum.


4
Bu, Chrome için tipiktir.
trincot

2
@trincot teşekkürler! Chrome'u kullandığımı söylemeyi unuttum ve sormadan önce başka bir tarayıcı denemedim. Referansınız var mı?
apieceofbart

16
DOM'un değiştirilmesi eşzamanlıdır. DOM'un oluşturulması aslında JavaScript yığını temizlendikten sonra gerçekleşir. developer.google.com/web/fundamentals/performance/rendering JavaScript> Stil> Düzen> Paint> Bileşik. (En azından Chrome için. Diğer tarayıcılar benzerdir.)
2017'de

2
sadece bir tahmin: bloke edici uyarı, tarayıcının bir yeniden boyama adımına ulaşmasını engeller, bu nedenle DOM değişmiş olsa da, yeniden boyamaya henüz izin verilmedi; yine, sadece bir tahmin.
zzzzBov

2
@qbolec bu videoyu kontrol edin: youtu.be/r8caVE_a5KQ
apieceofbart

Yanıtlar:


132

DOM'da yapabileceğiniz çoğu değişiklik gibi innerHTML'yi ayarlamak da eşzamanlıdır. Ancak, web sayfasını oluşturmak farklı bir hikaye.

(Unutmayın, DOM "Belge Nesne Modeli" anlamına gelir. Bu yalnızca bir "model", verilerin bir temsilidir. Kullanıcının ekranında gördüğü şey, modelin nasıl görünmesi gerektiğinin bir resmidir. Dolayısıyla, modeli değiştirmek anında olmaz resmi değiştirin - güncellenmesi biraz zaman alabilir.)

JavaScript'i çalıştırmak ve web sayfasını oluşturmak aslında ayrı ayrı gerçekleşir. (Etkinlik döngüden - check out sayfa pistlerinde her şeyden önce JavaScript, basitçe söylemek gerekirse bu mükemmel videoyu daha fazla ayrıntı için) ve daha sonra sonra tarayıcı kullanıcı görmek için web sayfasının herhangi bir değişiklik hale söyledi. Bu nedenle "engelleme" bu kadar önemli bir konudur - hesaplama açısından yoğun kod çalıştırmak, tarayıcının "JS çalıştır" adımını geçip "sayfayı oluştur" adımına geçmesini engeller, bu da sayfanın donmasına veya takılmasına neden olur.

Chrome'un ardışık düzeni şuna benzer:

görüntü açıklamasını buraya girin

Gördüğünüz gibi, tüm JavaScript önce gerçekleşir. Ardından sayfa şekillendirilir, düzenlenir, boyanır ve birleştirilir - "oluşturma". Bu ardışık düzenin tümü her çerçeveyi yürütmez. Varsa, hangi sayfa öğelerinin değiştiğine ve nasıl yeniden işlenmeleri gerektiğine bağlıdır.

Not: alert()aynı zamanda eşzamanlıdır ve JavaScript adımı sırasında yürütülür; bu nedenle, web sayfasındaki değişiklikleri görmeden önce uyarı iletişim kutusu görüntülenir.

Şimdi "Bekleyin, ardışık düzen içindeki o 'JavaScript' adımında tam olarak ne çalıştırılıyor? Tüm kodum saniyede 60 kez çalışıyor mu?" Cevap "hayır" dır ve JS olay döngüsünün nasıl çalıştığına geri döner. JS kodu yalnızca yığın içindeyse çalışır - olay dinleyicileri, zaman aşımları gibi şeylerden. Önceki videoya bakın (gerçekten).

https://developers.google.com/web/fundamentals/performance/rendering/


1
cevapladığınız için teşekkür ederim. Olay döngüsü vb. Hakkında bazı ayrıntılar biliyordum. Bu ardışık düzen çok mantıklı ama örneklerin gösterdiği gibi her tarayıcıda aynı değil. Diğer tarayıcılar uyarı göstermeden önce sayfanın yeniden boyanmasını beklerse, bu, düğmeye tıklamakla uyarının kendisini gösterme arasında büyük bir gecikme olabileceği anlamına gelir. Onunla daha sonra oynamaya çalışacağım.
apieceofbart

@apieceofbart Diğer tarayıcılar, kullanıcı uyarı penceresiyle ilgilenene kadar javascript öğelerini durdururken sayfayı eşzamansız olarak yeniden boyayabilir. Yeniden boyamanın gerçekleşmesini beklemeleri gerektiği anlamına gelmez.
Jonas Schäfer

27

Evet, eşzamanlıdır, çünkü bu çalışır (devam edin, konsolunuza yazın):

document.body.innerHTML = 'text';
alert(document.body.innerHTML);// you will see a 'text' alert

Sayfanın değiştiğini görmeden önce uyarıyı görmenizin nedeni, tarayıcı oluşturmanın daha fazla zaman alması ve javascript'in satır satır çalıştırması kadar hızlı olmamasıdır.


Teşekkürler, kontrol ettim. Ancak Chrome'a ​​özgü bir şey olmalı - diğer tarayıcılarda beklendiği gibi çalışıyor. Ya da bir sonraki javascript satırına geçmek için sayfanın yeniden boyanmasını beklemeleri onların kusurudur?
apieceofbart

3
Uyarı doğru metni gösteriyor mu? ( textbenim örneğimde) Bu, eşzamanlı olup olmadığı konusundaki sorunuza cevap verecektir. Tarayıcı oluşturma ve Javascript yürütme işlemi elma ve portakaldır :)
d -_- b


1
Sorunuz kelimenin tam anlamıyla "innerHTML eşzamansız mıdır?". Değer eşzamanlı olduktan hemen sonra kullanılabiliyorsa, hayır? Bence iç HTML'nin eşzamanlı kalitesi değil, sayfa oluşturma hakkında daha fazlasını sormak istiyorsunuz.
d -_- b

8
Evet, soru açıkça yanlıştı ama ne soracağımı bilmiyordum. Doğru olanı bilseydim, muhtemelen cevabı bulurdum. Kabalık etmek istemedim, yine de cevabın için teşekkürler!
apieceofbart

6

Gerçek innerHTMLözellik eşzamanlı olarak güncellenir, ancak bu değişikliğin neden olduğu görsel yeniden çizilir, eşzamansız olarak gerçekleşir.

DOM'un görsel oluşturma işlemi Chrome'da eşzamansızdır ve geçerli JavaScript işlev yığını temizlenene ve tarayıcı yeni bir olayı kabul etmekte özgür olana kadar gerçekleşmeyecektir. Diğer tarayıcılar, JavaScript kodunu ve tarayıcı oluşturmayı işlemek için ayrı diziler kullanabilir veya bir uyarı başka bir olayın yürütülmesini durdururken bazı olayların öncelik kazanmasına izin verebilir.

Bunu iki şekilde görebilirsiniz:

  1. Uyarınızdan for(var i=0; i<1000000; i++) { }önce eklerseniz , tarayıcıya yeniden çizim yapması için bolca zaman vermiş olursunuz, ancak bu yapılmamıştır, çünkü işlev yığını temizlenmemiştir ( addhala çalışıyor).

  2. Eğer alertbir eşzamansız ile geciktirirseniz setTimeout(function() { alert('random'); }, 1), yeniden çizim işlemi setTimeout tarafından geciktirilen fonksiyonun önüne geçecektir.

    • Bir zaman aşımı kullanırsanız 0, muhtemelen Chrome 0diğer etkinliklerden önce (veya en azından yeniden çizim olaylarından önce) zaman aşımlarına olay sırası önceliği verdiğinden , bu işe yaramaz .

Cevap verdiğiniz için teşekkürler! Lütfen setTimeout(func, 1)her seferinde işe yaramadığını bile unutmayın, bu videoyu kontrol edin: youtu.be/r8caVE_a5KQ
apieceofbart
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.