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.
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.
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.
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.
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.
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
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.
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.
Oluşturma ardışık düzeninin güncellenmesi maliyetli
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.
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 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.
Birleştirme
Bir sayfayı nasıl çizersiniz?
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?
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.
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.
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ş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.