Modern web tarayıcısına yakından bakış (3. bölüm)

Mariko Kosaka

Oluşturucu İşleminin iç işleyişi

Bu, tarayıcıların nasıl çalıştığını anlatan 4 bölümlük blog dizisinin 3. bölümüdür. Daha önce çok işlemli mimari ve gezinme akışını ele almıştık. Bu gönderide, oluşturucu işleminin içinde neler olduğuna bakacağız.

Oluşturucu işlemi, web performansının birçok unsurunu ilgilendirir. Oluşturucu işleminin içinde çok şey yaşandığından bu gönderi sadece genel bakış niteliğindedir. Daha ayrıntılı bilgi edinmek isterseniz Web'in Temelleri'nin Performans bölümünde çok daha fazla kaynak bulabilirsiniz.

Oluşturucu işlemleri web içeriklerini işler

Oluşturucu işlemi, bir sekmede olan her şeyden sorumludur. Bir oluşturucu işleminde, ana iş parçacığı, kullanıcıya gönderdiğiniz kodun büyük kısmını işler. Web çalışanı veya Service Worker kullanıyorsanız JavaScript'inizin bazı bölümleri, çalışan iş parçacıkları tarafından işlenir. Birleştirme ve kafes iş parçacıkları, bir sayfayı verimli ve sorunsuz bir şekilde oluşturmak için oluşturucu işlemlerinin içinde de çalıştırılır.

Oluşturucu işleminin temel işi HTML, CSS ve JavaScript'i kullanıcının etkileşimde bulunabileceği bir web sayfasına dönüştürmektir.

Oluşturucu işlemi
Şekil 1: Ana iş parçacığı, çalışan iş parçacığı, birleştirici iş parçacığı ve içinde bir kafes iş parçacığı bulunan oluşturucu işlemi

Ayrıştırma

DOM oluşturma

Oluşturucu işlemi, gezinme için bir kayıt mesajı alıp HTML verileri almaya başladığında, ana iş parçacığı metin dizesini (HTML) ayrıştırmaya ve bir Document Object Model'e (DOM) dönüştürmeye başlar.

DOM, web geliştiricisinin JavaScript aracılığıyla etkileşimde bulunabileceği veri yapısının ve API'nin yanı sıra sayfanın tarayıcı dahili gösterimidir.

Bir HTML belgesinin DOM olarak ayrıştırılması HTML Standardı tarafından tanımlanmıştır. HTML'yi bir tarayıcıya beslemenin hiçbir zaman hata vermediğini fark etmiş olabilirsiniz. Örneğin, </p> kapanış etiketinin eksik olması geçerli bir HTML'dir. Hi! <b>I'm <i>Chrome</b>!</i> gibi hatalı işaretleme (b etiketi, i etiketinden önce kapatılır) Hi! <b>I'm <i>Chrome</i></b><i>!</i> gibi hatalı işaretlemeler kabul edilir. Bunun nedeni, HTML spesifikasyonunun bu hataları incelikle inceleyecek şekilde tasarlanmış olmasıdır. Bu işlemlerin nasıl yapıldığını merak ediyorsanız HTML spesifikasyonunun "Hata işlemeye ve ayrıştırıcıdaki tuhaf durumlara giriş" bölümüne bakabilirsiniz.

Alt kaynak yükleniyor

Bir web sitesi genellikle resimler, CSS ve JavaScript gibi harici kaynakları kullanır. Bu dosyaların ağ veya önbellekten yüklenmesi gerekir. Ana iş parçacığı, DOM oluşturmak için ayrıştırma yaparken bunları bulduğu için tek tek isteyebilir, ancak bunu hızlandırmak için "önceden yükleme tarayıcısı" eşzamanlı olarak çalıştırılır. HTML belgesinde <img> veya <link> gibi öğeler varsa tarayıcı, HTML ayrıştırıcısı tarafından oluşturulan jetonlara önceden göz atar ve istekleri tarayıcı işlemindeki ağ iş parçacığına gönderir.

DOM
Şekil 2: HTML'yi ayrıştıran ve DOM ağacı oluşturma ana iş parçacığı

JavaScript, ayrıştırmayı engelleyebilir

HTML ayrıştırıcısı bir <script> etiketi bulduğunda, HTML belgesinin ayrıştırılmasını duraklatır ve JavaScript kodunu yüklemesi, ayrıştırması ve yürütmesi gerekir. Neden? JavaScript, tüm DOM yapısını değiştiren document.write() gibi şeyler kullanarak dokümanın şeklini değiştirebilir (HTML spesifikasyonundaki ayrıştırma modeline genel bakış iyi bir diyagrama sahiptir). Bu nedenle, HTML ayrıştırıcısının HTML belgesini ayrıştırmaya devam edebilmesi için JavaScript'in çalışmasını beklemesi gerekir. JavaScript yürütmede ne olduğunu merak ediyorsanız, V8 ekibinin bu konuyla ilgili konuşmaları ve blog yayınları vardır.

Tarayıcı için kaynakları nasıl yüklemek istediğinize dair ipucu

Web geliştiricilerinin, kaynakları düzgün bir şekilde yüklemek için tarayıcıya ipuçları gönderebilecekleri pek çok yöntem vardır. JavaScript'iniz document.write() kullanmıyorsa <script> etiketine async veya defer özelliğini ekleyebilirsiniz. Daha sonra tarayıcı, JavaScript kodunu eşzamansız olarak yükleyip çalıştırır, ayrıştırmayı engellemez. Uygun olması durumunda JavaScript modülünü de kullanabilirsiniz. <link rel="preload">, mevcut gezinme için kaynağın kesinlikle gerekli olduğunu ve mümkün olan en kısa sürede indirmek istediğinizi tarayıcıya bildirmenin bir yoludur. Bu konuyla ilgili daha fazla bilgiyi Kaynak Önceliklendirme - Tarayıcının Size Yardımcı Olmasını Sağlama bölümünde bulabilirsiniz.

Stil hesaplaması

DOM'ye sahip olmak, sayfanın nasıl görüneceğini bilmek yeterli değildir, çünkü sayfa öğelerini CSS'de biçimlendirebiliriz. Ana iş parçacığı CSS'yi ayrıştırır ve her bir DOM düğümü için hesaplanan stili belirler. Bu, CSS seçicilere dayalı olarak her bir öğeye ne tür stil uygulandığıyla ilgili bilgidir. Bu bilgileri Geliştirici Araçları'nın computed bölümünde görebilirsiniz.

Hesaplanan stil
Şekil 3: Hesaplanan stil eklemek için CSS'yi ayrıştıran ana iş parçacığı

Herhangi bir CSS sağlamasanız bile her DOM düğümünün hesaplanan bir stili olur. <h1> etiketi, <h2> etiketten daha büyük olarak gösterilir ve her öğe için kenar boşlukları tanımlanır. Bunun nedeni, tarayıcının varsayılan bir stil sayfasına sahip olmasıdır. Chrome'un varsayılan CSS'sinin nasıl olduğunu öğrenmek istiyorsanız kaynak koduna buradan bakabilirsiniz.

Düzen

Artık oluşturucu süreci, bir dokümanın yapısını ve her bir düğüme ait stilleri bilir, ancak bu, sayfayı oluşturmak için yeterli değildir. Bir resmi arkadaşınıza telefonla tarif etmeye çalıştığınızı düşünün. "Kırmızı büyük bir daire ve küçük mavi bir kare var", arkadaşınızın tablonun tam olarak neye benzediğini bilmesi için yeterli bilgi sağlamaz.

insan faks makinesi oyunu
Şekil 4: Bir tablonun önünde duran bir kişi ve diğer kişiye bağlı telefon hattı

Düzen, öğelerin geometrisini bulma işlemidir. Ana iş parçacığı DOM'de ve hesaplanan stillerde gezinir, x y koordinatları ve sınırlayıcı kutu boyutları gibi bilgiler içeren düzen ağacını oluşturur. Düzen ağacı, DOM ağacına benzer bir yapıya sahip olabilir ancak yalnızca sayfada görünenlerle ilgili bilgileri içerir. display: none uygulanırsa bu öğe, düzen ağacının parçası olmaz (ancak düzen ağacında visibility: hidden içeren bir öğe yer alır). Benzer şekilde, p::before{content:"Hi!"} gibi içeriğe sahip bir sözde öğe uygulanırsa, DOM'de bulunmasa bile düzen ağacına dahil edilir.

düzen
Şekil 5: Hesaplanmış stillerle DOM ağacının üzerinden geçen ve düzen ağacı oluşturan ana iş parçacığı
Şekil 6: Satır sonu değişikliği nedeniyle hareket eden bir paragrafın kutu düzeni

Bir sayfanın Düzenini belirlemek zor bir iştir. Üstten alta doğru blok akışı gibi en basit sayfa düzenlerinin bile, yazı tipinin ne kadar büyük olduğunu ve paragrafın hangi satırdan ayrılacağını dikkate alması gerekir. Çünkü bunlar bir paragrafın boyutunu ve şeklini etkiler. Bu da sonraki paragrafın nerede olması gerektiğini etkiler.

CSS, öğenin bir tarafa kaymasını sağlayabilir, taşma öğesini maskeleyebilir ve yazma yönünü değiştirebilir. Bu düzen aşamasının zor bir görev olduğunu tahmin edebilirsiniz. Chrome'da, mühendislerden oluşan bütün bir ekip düzen üzerinde çalışıyor. Ekibin çalışmalarının ayrıntılarını görmek istiyorsanız BlinkOn Konferansı'ndan birkaç konuşma kaydedilmiş ve bu konuşmalar oldukça ilginç görünüyor.

Boyama yapın

çizim oyunu
Şekil 7: Tuvalin önünde duran ve elinde fırça tutan bir kişi, önce daire mi yoksa kare mi çizmesi gerektiğini merak ediyor

Bir sayfayı oluşturmak için DOM, stil ve düzenin olması yeterli değildir. Diyelim ki bir resmi yeniden oluşturmaya çalışıyorsunuz. Öğelerin boyutunu, şeklini ve konumunu bilirsiniz ama yine de bunları hangi sırayla boyadığınıza karar vermeniz gerekir.

Örneğin, belirli öğeler için z-index ayarlanmış olabilir. Bu durumda, HTML'de yazılan öğeleri sıraya göre boyamak yanlış oluşturmaya neden olur.

z-endeksi başarısız
Şekil 8: Bir HTML işaretlemesi sırasına göre görünen ve Z-endeksi hesaba katılmadığı için resmin yanlış oluşturulmasına yol açan sayfa öğeleri

Bu boyama adımında, ana iş parçacığı düzen ağacında yürüyüş yaparak boyama kayıtları oluşturur. Boyama kaydı, "önce arka plan, ardından metin, sonra dikdörtgen" gibi bir boyama işlemi notudur. JavaScript kullanarak <canvas> öğesi üzerine çizim yaptıysanız bu işlem size tanıdık gelebilir.

boya kayıtları
Şekil 9: Düzen ağacında ilerleyen ve boya kayıtları oluşturan ana iş parçacığı

Oluşturma ardışık düzenini güncellemek maliyetli bir işlemdir

Şekil 10: Oluşturulma sırasına göre DOM+Stil, Düzen ve Boya ağaçları

Oluşturma ardışık düzeninde anlaşılması gereken en önemli nokta, her adımda yeni veriler oluşturmak için bir önceki işlemin sonucunun kullanılmasıdır. Örneğin, düzen ağacında bir değişiklik olursa Boya sırasının belgenin etkilenen bölümleri için yeniden oluşturulması gerekir.

Öğelere animasyon oluşturuyorsanız tarayıcının bu işlemleri her kare arasında çalıştırması gerekir. Ekranlarımızın çoğu, ekranı saniyede 60 kez (60 fps) yeniler; siz her karede ekrandaki öğeleri hareket ettirdiğinizde animasyon insan gözleri için akıcı bir şekilde görünür. Bununla birlikte, animasyonda aradaki kareler eksikse sayfa "titreşimli" görünür.

eksik karelerden jage jank
Şekil 11: Zaman çizelgesindeki animasyon kareleri

Oluşturma işlemleriniz ekran yenilemeye ayak uydursa bile bu hesaplamalar ana iş parçacığında çalışır. Bu da uygulamanız JavaScript'i çalıştırırken iş parçacığının engellenebileceği anlamına gelir.

JavaScript&#39;ten jage jank
Şekil 12: Zaman çizelgesindeki animasyon kareleri ancak bir kare JavaScript tarafından engelleniyor

JavaScript işlemini küçük parçalara bölebilir ve requestAnimationFrame() kullanarak her karede çalışacak şekilde planlayabilirsiniz. Bu konu hakkında daha fazla bilgi için lütfen JavaScript Yürütmeyi Optimize Etme bölümüne bakın. Ana iş parçacığının engellenmesini önlemek için Web Çalışanlarında JavaScript'inizi de çalıştırabilirsiniz.

animasyon çerçevesi iste
Şekil 13: Animasyon çerçevesi bulunan bir zaman çizelgesinde çalışan küçük JavaScript parçaları

Birleştiriliyor

Nasıl sayfa çizersiniz?

Şekil 14: Naif pikselleştirme işleminin animasyonu

Tarayıcı dokümanın yapısını, her bir öğenin stilini, sayfanın geometrisini ve boyama sırasını bildiğine göre artık sayfayı nasıl çizer? Bu bilgileri ekranda piksellere dönüştürmeye rasterleştirme denir.

Bunu yönetmenin naif bir yolu, görüntü alanının içindeki bölümleri kafeslemek olabilir. Kullanıcı sayfayı kaydırırsa kafesli çerçeveyi hareket ettirin ve daha fazla pikselleştirerek eksik kısımları doldurun. Chrome, ilk yayınlandığında pikselleştirmeyi bu şekilde ele aldı. Ancak modern tarayıcı, birleştirme adı verilen daha karmaşık bir işlem çalıştırır.

Birleştirme nedir?

Şekil 15: Birleştirme işleminin animasyonu

Birleştirme, bir sayfanın bölümlerini katmanlara ayırmak, bunları ayrı ayrı rasterleştirmek ve birleştirici iş parçacığı adı verilen ayrı bir iş parçacığında bir sayfa olarak birleştirmek için kullanılan bir tekniktir. Kaydırma gerçekleşirse katmanlar zaten pikselleştirildiği için yapmanız gereken tek şey yeni bir kareyi birleştirmektir. Animasyonu da aynı şekilde katmanları hareket ettirip yeni bir kare ekleyerek yapabilirsiniz.

Web sitenizin Geliştirici Araçları'nda Katmanlar panelini kullanarak katmanlara nasıl bölündüğünü görebilirsiniz.

Katmanlara bölünme

Hangi öğelerin hangi katmanlarda olması gerektiğini bulmak için ana iş parçacığı, katman ağacını oluşturmak üzere düzen ağacında ilerler (bu bölüme, Geliştirici Araçları performans panelinde "Katman Ağacı Güncelleme" adı verilir). Bir sayfanın ayrı katman olarak kullanılması gereken belirli bölümleri (ör. kayan yan menü) bu seçeneği almıyorsa CSS'de will-change özelliğini kullanarak tarayıcıya ipucu verebilirsiniz.

katman ağacı
Şekil 16: Katman ağacı oluşturan düzen ağacında ilerleyen ana iş parçacığı

Katmanları her öğeye vermek cazip gelse de fazla sayıda katmandan faydalanmak, bir sayfanın her karede küçük parçalarını pikselleştirmektense daha yavaş işleme neden olabilir. Bu nedenle, uygulamanızın oluşturma performansını ölçmeniz çok önemlidir. Konu hakkında daha fazla bilgi için Yalnızca Birleştirici Mülklere Bağlı Kalma ve Katman Sayısını Yönetme bölümüne bakın.

Ana iş parçacığından kafes ve birleşik öğe

Katman ağacı oluşturulduktan ve boyama siparişleri belirlendikten sonra, ana iş parçacığı bu bilgileri birleştirici iş parçacığına kaydeder. Birleştirici iş parçacığı daha sonra her bir katmanı pikselleştirir. Bir katman, bir sayfanın tüm uzunluğu kadar büyük olabilir. Bu nedenle, birleştirici iş parçacığı bunları karolara böler ve her bir parçayı kafes ileti dizilerine gönderir. Kafes iş parçacıkları her parçayı rasterleştirir ve GPU belleğinde depolar.

kafes
Şekil 17: Karoların bit eşlemini oluşturan ve GPU'ya gönderen kafes iş parçacıkları

Birleştirici iş parçacığı, farklı kafes iş parçacıklarına öncelik verebilir. Böylece, görüntü alanındaki (veya yakındaki) öğeler ilk önce pikselleştirilebilir. Bir katman, yakınlaştırma işlemi gibi şeyleri işlemek amacıyla farklı çözünürlükler için birden fazla döşeme de içerir.

Karolar pikselleştirildikten sonra birleştirici iş parçacığı çizme dörtlü adı verilen parça bilgilerini toplayarak bir birleştirici çerçevesi oluşturur.

Dörtlü çekiliş Parçanın bellekteki konumu ve sayfa birleştirme dikkate alınarak karonun çizileceği sayfanın neresinde olduğu gibi bilgileri içerir.
Birleştirme çerçevesi Sayfanın çerçevesini temsil eden çizim dörtlüleri koleksiyonu.

Daha sonra, birleştirici çerçeve IPC aracılığıyla tarayıcı işlemine gönderilir. Bu noktada, tarayıcı kullanıcı arayüzü değişikliği için kullanıcı arayüzü iş parçacığından veya uzantılar için diğer oluşturucu işlemlerinden başka bir oluşturucu çerçevesi eklenebilir. Bu birleştirici kareler, ekranda görüntülemek için GPU'ya gönderilir. Bir kaydırma etkinliği gelirse birleştirici iş parçacığı, GPU'ya gönderilecek başka bir birleştirici karesi oluşturur.

birleştirme
Şekil 18: Birleştirme çerçevesi oluşturan birleştirme iş parçacığı. Çerçeve, tarayıcı işlemine, ardından GPU'ya gönderilir

Birleştirmenin avantajı, işlemin ana iş parçacığı içermeden yapılmasıdır. Birleştirici iş parçacığının stil hesaplamasını veya JavaScript'in yürütülmesini beklemesine gerek yoktur. Bu nedenle, sorunsuz performans için yalnızca animasyonların birleştirilmesi en iyi seçenek olarak kabul edilir. Düzenin veya boyanın tekrar hesaplanması gerekiyorsa ana iş parçacığı dahil edilmelidir.

Son adım

Bu gönderide, oluşturma ardışık düzeninden ayrıştırmadan birleştirmeye kadar çeşitli işlemleri inceledik. Artık bir web sitesinin performans optimizasyonu hakkında daha fazla bilgi edinebileceğinizi umuyoruz.

Bu serinin bir sonraki ve son gönderisinde, oluşturucu ileti dizisine daha ayrıntılı bir şekilde bakıp mouse move ve click gibi kullanıcı girişleri geldiğinde ne olduğunu göreceğiz.

Gönderiyi beğendiniz mi? Gelecekteki bir gönderi için sorularınız veya önerileriniz varsa aşağıdaki yorum bölümüne ya da Twitter'da @kosamari adresine yazın.

Sonraki: Giriş, birleştiriciye geliyor