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

Mariko Kosaka

Oluşturucu Sürecinin iç çalışmaları

Bu, tarayıcıların nasıl çalıştığını konu alan 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 yayında, oluşturucu sürecinin içinde neler olduğuna bakacağız.

Oluşturucu süreci, web performansının birçok yönünü etkiler. Oluşturucu süreci içinde çok fazla şey olduğundan bu gönderi sadece genel bir bakış niteliğindedir. Daha ayrıntılı bilgi edinmek istiyorsanız Web'in Temelleri'nin Performans bölümünde daha pek çok kaynak bulunmaktadır.

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

Oluşturucu işlemi, bir sekme içinde olan her şeyden sorumludur. Oluşturucu sürecinde, ana iş parçacığı kullanıcıya gönderdiğiniz kodun çoğunu işler. Web çalışanı veya hizmet çalışanı kullanıyorsanız JavaScript'inizin bazı bölümleri, çalışan iş parçacıkları tarafından işlenir. Bir sayfanın verimli ve sorunsuz şekilde oluşturulması için toplayıcı ve kafes iş parçacıkları da oluşturucu işlemlerinin içinde çalıştırılır.

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

Oluşturucu süreci
Şekil 1: Ana iş parçacığı, çalışan iş parçacıkları, birleştirici iş parçacığı ve içinde kafes iş parçacığı içeren oluşturucu süreci

Ayrıştırılıyor

DOM oluşturma

Oluşturucu işlemi, gezinme için bir kaydetme mesajı aldığında ve HTML verilerini almaya başladığında, ana iş parçacığı metin dizesini (HTML) ayrıştırmaya ve bunu bir Dulaf Object Model'ine (DOM) dönüştürmeye başlar.

DOM, tarayıcı tarafından sayfanın dahili temsilinin yanı sıra web geliştiricisinin JavaScript aracılığıyla etkileşimde bulunabileceği veri yapısı ve API'dir.

Bir HTML belgesinin DOM olarak ayrıştırılması HTML Standardı tarafından tanımlanır. HTML'yi tarayıcıya aktarmanın hiçbir zaman hataya neden olmadığını 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şaretlemeler (b etiketi i etiketinden önce kapatılır), Hi! <b>I'm <i>Chrome</i></b><i>!</i> yazmışsınız gibi değerlendirilir. Bunun nedeni, HTML spesifikasyonunun bu hataları incelikle ele alacak şekilde tasarlanmasıdır. Bunların nasıl yapıldığını merak ediyorsanız HTML spesifikasyonunun "Ayrıştırıcıdaki hata işleme ve tuhaf durumlara giriş" bölümüne göz atabilirsiniz.

Alt kaynak yükleniyor

Bir web sitesi genellikle resim, CSS ve JavaScript gibi harici kaynakları kullanır. Bu dosyaların ağdan veya önbellekten yüklenmesi gerekir. Ana iş parçacığı, DOM oluşturmak için ayrıştırma sırasında bunları bulduğunda bunları tek tek isteyebilir, ancak hızlandırmak için "tarayıcıyı önceden yükleme" eş zamanlı olarak çalıştırılır. HTML belgesinde <img> veya <link> gibi öğeler varsa tarayıcı, HTML ayrıştırıcı tarafından oluşturulan jetonlara 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şturan ana iş parçacığı

JavaScript, ayrıştırma işlemini engelleyebilir

HTML ayrıştırıcı 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? Çünkü JavaScript, tüm DOM yapısını değiştiren document.write() gibi şeyleri kullanarak belgenin şeklini değiştirebilir (HTML spesifikasyonunda ayrıştırma modeline genel bakış güzel bir diyagrama sahiptir). Bu nedenle HTML ayrıştırıcısının HTML dokümanını ayrıştırmaya devam edebilmesi için JavaScript'in çalışmasını beklemesi gerekir. JavaScript yürütme işleminin sonuçlarını merak ediyorsanız V8 ekibinin bu konuda konuşmaları ve blog yayınları bulunmaktadır.

Kaynakları nasıl yüklemek istediğinize dair tarayıcıya ipucu

Web geliştiricilerinin, kaynakları düzgün şekilde yüklemek için tarayıcıya ipuçları gönderebileceği pek çok yol vardır. JavaScript'iniz document.write() kullanmıyorsa <script> etiketine async veya defer özelliğini ekleyebilirsiniz. Ardından tarayıcı, JavaScript kodunu eşzamansız olarak yükleyip çalıştırır ve ayrıştırma işlemini engellemez. Uygunsa JavaScript modülünü de kullanabilirsiniz. <link rel="preload">, mevcut gezinme için kaynağın kesinlikle gerekli olduğu ve en kısa sürede dosyayı indirmek istediğiniz konusunda tarayıcıya bilgi vermenin bir yoludur. Kaynak Önceliklendirme: Tarayıcının Size Yardımcı Olmasını Sağlama başlıklı makaleden bu konu hakkında daha fazla bilgi edinebilirsiniz.

Stil hesaplaması

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

Hesaplanan stil
Şekil 3: Hesaplanan stili 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 vardır. <h1> etiketi, <h2> etiketinden daha büyük görüntülenir 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 ne olduğunu öğrenmek istiyorsanız kaynak koduna buradan göz atabilirsiniz.

Düzen

Artık oluşturucu süreci, bir dokümanın yapısını ve her düğüme ilişkin stilleri bilir, ancak bu bilgi, bir sayfayı oluşturmak için yeterli değildir. Bir resmi arkadaşınıza telefonda anlatmaya çalıştığınızı hayal edin. "Büyük kırmızı bir daire ve küçük mavi bir kare var", arkadaşınızın resmin tam olarak nasıl görüneceğini bilmesi için yeterli bilgi değildir.

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

Düzen, öğelerin geometrisini bulmaya yönelik bir süreçtir. Ana iş parçacığı, DOM ve hesaplanan stillerde ilerler ve x y koordinatları ve sınırlayıcı kutu boyutları gibi bilgilerin bulunduğu 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ı değildir (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 gerçek olmayan bir sınıf uygulanırsa bu sınıf, DOM'de yer almasa bile düzen ağacına dahil edilir.

düzen
Şekil 5: Hesaplanan 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. Yukarıdan aşağıya blok akışı gibi en basit sayfa düzeni bile yazı tipinin ne kadar büyük olduğunu ve satırların nereye yerleştirileceğini dikkate almalıdır. Çü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ı, taşma öğesini maskeleyebilir ve yazma yönlerini değiştirebilir. Tahmin edebileceğiniz gibi, bu düzen aşamasının zorlu bir görevi var. Chrome'da, mühendislerden oluşan bütün bir ekip düzen üzerinde çalışır. Çalışmalarının ayrıntılarını görmek istiyorsanız BlinkOn Conference'taki birkaç konuşmayı kaydedilmiş ve izlemek oldukça ilgi çekicidir.

Boyama yapın

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

Bir sayfayı oluşturmak için DOM, stil ve düzene sahip olmak yeterli olmaz. Bir resmi yeniden üretmeye çalıştığınızı varsayalım. Öğelerin boyutunu, şeklini ve konumunu bilirsiniz ancak yine de bunları hangi sırayla boyayacağınıza karar vermeniz gerekir.

Örneğin, belirli öğeler için z-index ayarlanmış olabilir. Bu durumda, öğeleri HTML içinde yazılan öğelerin sırasına göre boyamak yanlış oluşturma işlemine neden olur.

z-endeksi başarısız
Şekil 8: Sayfa öğeleri, HTML işaretlemesi sırasında görünüyor ve Z-endeksi dikkate alınmadığından yanlış oluşturulmuş resme neden oluyor

Bu boyama adımında, ana iş parçacığı boya kayıtları oluşturmak için düzen ağacında gezinir. Boya kaydı ise "önce arka plan, ardından metin, sonra dikdörtgen" gibi bir boyama işlemiyle ilgilidir. <canvas> öğesini JavaScript kullanarak çizdiyseniz bu süreç size tanıdık gelebilir.

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

Oluşturma ardışık düzeninin güncellenmesi maliyetli

Ş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 şey, her adımda yeni veriler oluşturmak için önceki işlemin sonucunun kullanılmasıdır. Örneğin, düzen ağacında bir değişiklik olursa belgenin etkilenen kısımları için Boyama sırasının yeniden oluşturulması gerekir.

Öğelere animasyon ekliyorsanı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; animasyon, her karede ekranda bir şeyler hareket ettirildiğinde insan gözleri tarafından yumuşak bir şekilde görünür. Ancak animasyonda aradaki kareler eksik olursa sayfa "donuk" olarak görünür.

eksik kareler nedeniyle olumsuz jage
Şekil 11: Zaman çizelgesindeki animasyon kareleri

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

JavaScript tarafından 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ı engellememek için Web Çalışanlarında JavaScript'inizi de çalıştırabilirsiniz.

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

Birleştirme

Bir sayfayı nasıl çizersiniz?

Şekil 14: Naif kafes oluşturma işleminin animasyonu

Tarayıcı artık belgenin yapısını, her bir öğenin stilini, sayfanın geometrisini ve boyama sırasını bildiğine göre sayfayı nasıl çizer? Bu bilgileri ekranda piksellere dönüştürmek, pikselleştirme olarak adlandırılır.

Bunu halletmenin naif bir yolu, görüntü alanının içindeki kafes parçalarını kullanmaktır. Kullanıcı sayfayı kaydırırsa kafesli çerçeveyi taşıyın ve daha fazla kafes oluşturarak eksik kısımları doldurun. Chrome, ilk kullanıma sunulduğunda pikselleştirmeyi bu şekilde ele aldı. Ancak, modern tarayıcı, birleştirme adı verilen daha karmaşık bir işlemi çalıştırır.

Birleştirme nedir?

Şekil 15: Birleştirme işleminin animasyonu

Birleştirme, bir sayfanın parçalarını katmanlara ayırmak, bunları ayrı olarak pikselleştirmek ve birleştirici iş parçacığı adı verilen ayrı bir iş parçacığında sayfa olarak birleştirmek için kullanılan bir tekniktir. Kaydırma olursa, katmanlar zaten pikselleştirilmiş olduğundan tek yapması gereken yeni bir kare oluşturmaktır. Animasyonlar da aynı şekilde katmanların taşınması ve yeni bir karenin birleştirilmesiyle elde edilebilir.

Katmanlar panelini kullanarak web sitenizin nasıl katmanlara ayrıldığını Geliştirici Araçları'nda görebilirsiniz.

Katmanlara bölme

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 adım adım ilerler (bu bölüme Geliştirici Araçları performans panelinde "Katman Ağacı Güncelle" adı verilir). Ayrı katman olması gereken bir sayfanın belirli bölümlerinde (yan yana kaydırılan menü gibi) katmana ulaşılmı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 yürüyen ana iş parçacığı

Her öğeye katman vermek cazip gelebilir, ancak fazla sayıda katmanda birleştirmek, her karede bir sayfanın küçük parçalarını pikselleştirmekten daha yavaş çalışmaya neden olabilir. Bu nedenle, uygulamanızın oluşturma performansını ölçmeniz çok önemlidir. Konu hakkında daha fazla bilgi için bkz. Yalnızca Bileşik Özelliklere Bağlılık ve Katman Sayısını Yönetme.

Ana iş parçacığının kafes ve birleşik

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 karoyu kafes iş parçacığına gönderir. Kafes iş parçacıkları her bir parçayı rasterleştirir ve GPU belleğinde depolar.

kafes
Şekil 17: Karoların bit eşlemini oluşturan ve GPU'ya gönderme yapan 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) şeylerin önce kafesli olması sağlanır. Bir katman, yakınlaştırma işlemi gibi özelliklerin işlenebilmesi için farklı çözünürlüklere yönelik birden fazla parçaya da sahiptir.

Karolar kafeslendikten sonra, birleştirici iş parçacığı birleştirici çerçevesi oluşturmak için çekme dörtlüleri adlı karo bilgilerini toplar.

Dörtlü beraberlik Karonun bellekteki konumu ve sayfa birleştirme dikkate alınarak sayfada çizileceği yer gibi bilgileri içerir.
Birleştirme çerçevesi Bir sayfanın çerçevesini temsil eden dörtlü setler koleksiyonu.

Daha sonra, IPC aracılığıyla tarayıcı işlemine bir birleştirici çerçeve 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ülenmesi 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 çerçeve oluşturur.

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

Birleştirmenin avantajı, ana iş parçacığını içermeden yapılmasıdır. Birleştirici iş parçacığının, stil hesaplaması veya JavaScript yürütmesi için beklemesi gerekmez. Bu nedenle, yalnızca animasyonların birleştirilmesi sorunsuz bir performans için en iyi seçenek olarak değerlendirilir. Düzen veya boyamanın tekrar hesaplanması gerekiyorsa ana iş parçacığı dahil edilmelidir.

Özet

Bu gönderide, ayrıştırmadan birleştirmeye kadar uzanan oluşturma ardışık düzenini inceledik. Artık bir web sitesinin performans optimizasyonu hakkında daha fazla bilgi sahibi olduğunuzu umuyoruz.

Bu dizinin bir sonraki ve son gönderisinde, birleştirici ileti dizisini daha ayrıntılı bir şekilde inceleyip mouse move ve click gibi kullanıcı girişleri geldiğinde ne olacağını göreceğiz.

Gönderiyi beğendiniz mi? Gelecekteki gönderimlerle ilgili sorularınız veya önerileriniz varsa aşağıdaki yorum bölümünden ya da Twitter'daki @kosamari adresinden bize yanıt vermekten memnun olurum.

Sıradaki: Giriş, birleştiriciye geliyor