renderNG ayrıntılı incelemesi: BlinkNG

Stefan Zager
Stefan Zager
Chris Harrelson
Chris Harrelson

Blink, Chromium'un web platformunu uygulamasını ifade eder ve oluşturmadan önce oluşturma işleminin tüm aşamalarını kapsar ve oluşturucu taahhütüyle sona erer. Blink oluşturma mimarisi hakkında daha fazla bilgiyi bu serinin önceki makalesinde bulabilirsiniz.

Blink, 1998'den kalma KHTML'nin bir çatalı olan WebKit'in bir çatalı olarak ortaya çıktı. Chromium'daki en eski (ve en kritik) kodlardan bazılarını içeriyordu ve 2014'e gelindiğinde artık eskidiğini gösteriyordu. O yıl, Blink kodunun organizasyonu ve yapısındaki uzun süredir devam eden eksiklikleri gidermek amacıyla BlinkNG olarak adlandırdığımız bir dizi iddialı projeye başladık. Bu makalede, BlinkNG ve bileşen projeleri incelenmektedir: Bu projeleri neden yaptığımız, neleri başardıkları, tasarımlarını şekillendiren temel ilkeler ve gelecekte iyileştirme fırsatları sundukları.

BlinkNG'den önce ve sonra oluşturma ardışık düzeni.

NG öncesi oluşturma

Blink'teki oluşturma ardışık düzeni her zaman kavramsal olarak aşamalara (stil, düzen, boya vb.) bölünmüştür ancak soyutlama engelleri sızıntılıdır. Genel olarak, oluşturmayla ilişkili veriler uzun ömürlü ve değiştirilebilir nesnelerden oluşuyordu. Bu nesneler herhangi bir zamanda değiştirilebilir ve değiştirilmiştir. Ayrıca, art arda yapılan oluşturma güncellemeleri tarafından sık sık geri dönüştürülüp yeniden kullanılmıştır. Aşağıdaki gibi basit soruları güvenilir bir şekilde yanıtlamak mümkün değildi:

  • Stil, düzen veya boya çıkışının güncellenmesi gerekiyor mu?
  • Bu veriler ne zaman "nihai" değerini alacak?
  • Bu verileri ne zaman değiştirmem uygundur?
  • Bu nesne ne zaman silinecek?

Buna örnek olarak aşağıdakiler verilebilir:

Stil, stil sayfalarına göre ComputedStyle oluşturur ancak ComputedStyle sabit değildir; bazı durumlarda daha sonraki ardışık düzen aşamaları tarafından değiştirilir.

Stil, LayoutObject ağacı oluşturur ve ardından düzen bu nesneleri boyut ve konumlandırma bilgileriyle ekler. Bazı durumlarda düzen, ağaç yapısını bile değiştirebilir. layout öğesinin girişleri ile çıkışları arasında net bir ayrım yoktu.

Stil, kompozisyon sürecini belirleyen aksesuar veri yapıları oluştururdu ve bu veri yapıları, stil'den sonraki her aşamada yerinde değiştirilirdi.

Daha alt düzeyde, oluşturma veri türleri büyük ölçüde özel ağaçlardan (ör. DOM ağacı, stil ağacı, düzen ağacı, boyama mülkü ağacı) oluşur ve oluşturma aşamaları, yinelenen ağaç yürüyüşleri olarak uygulanır. İdeal olarak, ağaç yürüyüşü kapsalı olmalıdır: Belirli bir ağaç düğümünü işlerken, bu düğümde köklenen alt ağacın dışındaki hiçbir bilgiye erişmemeliyiz. Bu durum, RenderingNG'den önce hiç doğru değildi; ağaç yürüyüşleri, işlenen düğümün atalarından gelen bilgilere sık sık erişiyordu. Bu durum, sistemi çok hassas ve hataya açık hale getirdi. Ayrıca, ağaç yürüyüşünü ağacın kökünden başka bir yerden başlatmak mümkün değildi.

Son olarak, kodda oluşturma ardışık düzenine birçok giriş noktası vardı: JavaScript tarafından tetiklenen zorunlu düzenler, belge yükleme sırasında tetiklenen kısmi güncellemeler, etkinlik hedeflemeye hazırlanmak için zorunlu güncellemeler, görüntüleme sistemi tarafından istenen planlanmış güncellemeler ve yalnızca test koduna sunulan özel API'ler bunlardan bazılarıdır. Oluşturma ardışık düzeninde birkaç yeniden itirazlı ve yeniden giren yol bile vardı (yani bir aşamanın ortasından başka bir aşamanın başına atlama). Bu ilk katılım noktalarının her birinin kendine özgü davranışları vardı ve bazı durumlarda oluşturma çıktısı, oluşturma güncellemesinin nasıl tetiklendiğine bağlıydı.

Yaptığımız değişiklikler

BlinkNG, büyük ve küçük birçok alt projeden oluşur. Bu projelerin tümü, daha önce açıklanan mimari eksiklikleri ortadan kaldırmayı amaçlar. Bu projeler, oluşturma ardışık düzenini daha gerçek bir ardışık düzen haline getirmek için tasarlanmış birkaç temel ilkeyi paylaşır:

  • Tek tip giriş noktası: Her zaman ardışık düzene başından girmeliyiz.
  • Fonksiyonel aşamalar: Her aşamanın iyi tanımlanmış giriş ve çıkışları olmalı, davranışı fonksiyonel (yani, belirlenebilir ve tekrarlanabilir) olmalı ve çıkışlar yalnızca tanımlanmış girişlere bağlı olmalıdır.
  • Sabit girişler: Herhangi bir aşamanın girişleri, aşama çalışırken etkili bir şekilde sabit olmalıdır.
  • Değiştirilemez çıkışlar: Bir aşama tamamlandıktan sonra, çıkışları oluşturma güncellemesinin geri kalanı için değiştirilemez olmalıdır.
  • Kontrol noktası tutarlılığı: Her aşamanın sonunda, o ana kadar oluşturulan oluşturma verileri kendi içinde tutarlı bir durumda olmalıdır.
  • İşin tekilleştirilmesi: Her şey yalnızca bir kez hesaplanır.

BlinkNG alt projelerinin tam listesini okumak sıkıcı olabilir ancak aşağıda, özellikle önemli olanlardan birkaçı verilmiştir.

Doküman yaşam döngüsü

DocumentLifecycle sınıfı, oluşturma ardışık düzeni boyunca kaydettiğimiz ilerlemeyi izler. Bu sayede, daha önce listelenen değişmezlikleri zorunlu kılan temel kontroller yapabiliriz. Örneğin:

  • Bir ComputedStyle mülkü değiştiriliyorsa belge yaşam döngüsü kInStyleRecalc olmalıdır.
  • DocumentLifecycle durumu kStyleClean veya daha yeniyse NeedsStyleRecalc(), bağlı tüm düğümler için false döndürmelidir.
  • Boya yaşam döngüsü aşamasına girerken yaşam döngüsü durumu kPrePaintClean olmalıdır.

BlinkNG'yi uygulama sürecinde, bu değişmezlikleri ihlal eden kod yollarını sistematik olarak ortadan kaldırdık ve gerileme yaşamamak için kod boyunca daha birçok iddia ekledik.

Düşük düzey oluşturma koduna bakmak için kendinizi bir çıkmazda bulduysanız "Buraya nasıl geldim?" diye düşünebilirsiniz. Daha önce de belirtildiği gibi, oluşturma ardışık düzenine çeşitli giriş noktaları vardır. Daha önce bu, yinelenen ve yeniden giren çağrı yollarını ve ardışık düzene baştan başlamak yerine bir ara aşamada girdiğimiz yerleri içeriyordu. BlinkNG sırasında bu çağrı yollarını analiz ettik ve hepsinin iki temel senaryoya indirgenebileceğini belirledik:

  • Tüm oluşturma verilerinin güncellenmesi gerekir. Örneğin, görüntüleme için yeni pikseller oluşturulurken veya etkinlik hedefleme için isabet testi yapılırken.
  • Belirli bir sorgu için tüm oluşturma verileri güncellenmeden yanıtlanabilecek güncel bir değere ihtiyacımız var. Buna çoğu JavaScript sorgusu (ör. node.offsetTop) dahildir.

Artık oluşturma ardışık düzenine bu iki senaryoya karşılık gelen yalnızca iki giriş noktası vardır. Yeniden giren kod yolları kaldırıldı veya yeniden düzenlendi. Artık ardışık düzene bir ara aşamadan başlayarak girmek mümkün değil. Bu sayede, oluşturma güncellemelerinin tam olarak ne zaman ve nasıl gerçekleştiğiyle ilgili birçok soru yanıtlanmış ve sistemin davranışı hakkında daha kolay çıkarım yapılabilir hale gelmiştir.

Boru hattı stili, düzen ve ön boyama

Boya öncesi oluşturma aşamaları toplu olarak aşağıdakilerden sorumludur:

  • DOM düğümleri için nihai stil özelliklerini hesaplamak üzere stil basamağı algoritmasının çalıştırılması.
  • Dokümanın kutu hiyerarşisini temsil eden düzen ağacı oluşturulur.
  • Tüm kutuların boyut ve konum bilgilerini belirleme.
  • Boyama için alt piksel geometrisini yuvarlama veya tam piksel sınırlarına sabitleme.
  • Birleştirilmiş katmanların özelliklerini belirleme (affine dönüşüm, filtreler, opaklık veya GPU hızlandırıcısı kullanılabilecek başka herhangi bir şey).
  • Önceki boyama aşamasından bu yana hangi içeriğin değiştiğini ve boyanması veya yeniden boyanması gerektiğini belirleme (boya geçersiz kılma).

Bu liste değişmedi ancak BlinkNG'den önce bu çalışmaların çoğu, çok sayıda yinelenen işlev ve yerleşik verimsizliklerle birden fazla oluşturma aşamasına yayılmış, geçici bir şekilde yapılmıştı. Örneğin, düğümlerin nihai stil özelliklerini hesaplamaktan her zaman birincil olarak stil aşaması sorumlu olmuştur. Ancak nihai stil özelliği değerlerini stil aşaması tamamlanana kadar belirlemediğimiz birkaç özel durum vardı. Oluşturma sürecinde, stil bilgilerinin eksiksiz ve değiştirilemez olduğunu kesin olarak söyleyebileceğimiz resmi veya zorunlu bir nokta yoktu.

BlinkNG öncesi sorunlara iyi bir örnek de boya geçersizliğidir. Daha önce boya geçersiz kılma işlemi, boyaya kadar tüm oluşturma aşamalarında dağıtılıyordu. Stil veya düzen kodunu değiştirirken, boyama geçersiz kılma mantığında hangi değişikliklerin yapılması gerektiğini bilmek zordu ve geçersiz kılma işleminin eksik veya fazla yapılmasına yol açan hatalar yapmak kolaydı. Eski boya geçersiz kılma sisteminin incelikleri hakkında daha fazla bilgiyi bu serinin LayoutNG'ye ayrılmış makalesinde bulabilirsiniz.

Boyama için alt piksel düzen geometrisini tam piksel sınırlarına sabitleme, aynı işlevin birden fazla şekilde uygulandığı ve çok fazla gereksiz çalışma yaptığımız bir örnektir. Boyama sistemi tarafından kullanılan bir piksel yakalama kod yolu ve boyama kodu dışında piksel yakalanmış koordinatların tek seferlik, anında hesaplanmasına ihtiyaç duyduğumuzda kullanılan tamamen ayrı bir kod yolu vardı. Her uygulamanın kendi hataları olduğunu ve sonuçların her zaman aynı olmadığını söylemeye gerek yok. Bu bilgiler önbelleğe alınmadığından sistem bazen aynı hesaplamayı tekrar tekrar gerçekleştiriyordu. Bu da performansı olumsuz yönde etkileyen bir faktördü.

Boya öncesi oluşturma aşamalarının mimari eksikliklerini ortadan kaldıran bazı önemli projeleri aşağıda bulabilirsiniz.

Project Squad: Stil aşamasını ardışık düzene alma

Bu projede, stil aşamasında düzgün bir şekilde ardışık düzene sokulmayı engelleyen iki temel eksiklik ele alındı:

Stil aşamasının iki ana çıkışı vardır: CSS basamaklı algoritmasının DOM ağacı üzerinde çalıştırılmasının sonucunu içeren ComputedStyle ve düzen aşaması için işlemlerin sırasını belirleyen bir LayoutObjects ağacı. Kavramsal olarak, basamaklı algoritmanın çalıştırılması kesinlikle düzen ağacı oluşturulmadan önce gerçekleşmelidir. Ancak daha önce bu iki işlem iç içe yerleştirilmişti. Project Squad, bu ikisini birbirinden farklı ve sıralı aşamalara ayırmayı başardı.

Daha önce ComputedStyle, stil yeniden hesaplaması sırasında her zaman nihai değerini almıyordu; ComputedStyle'ün daha sonraki bir ardışık düzen aşamasında güncellendiği birkaç durum vardı. Proje Ekibi, bu kod yollarını başarıyla yeniden yapılandırdı. Böylece ComputedStyle, stil aşamasından sonra hiçbir zaman değiştirilmedi.

LayoutNG: Düzenleme aşamasını ardışık düzene alma

RenderingNG'nin temel taşlarından biri olan bu devasa proje, düzen oluşturma aşamasının tamamen yeniden yazılmasını sağladı. Projenin tamamını burada ele almayacağız ancak BlinkNG projesinin genel olarak dikkate değer birkaç yönü vardır:

  • Daha önce düzen aşaması, stil aşaması tarafından oluşturulan bir LayoutObject ağacı alıyordu ve ağacı boyut ve konum bilgileriyle ek açıklamayla işaretliyordu. Bu nedenle, girişler çıkışlardan net bir şekilde ayrılamadı. LayoutNG, düzenin birincil, salt okunur çıkışı olan ve sonraki oluşturma aşamalarının birincil girişi olarak hizmet veren parça ağacını kullanıma sundu.
  • LayoutNG, kapsama özelliğini düzene getirdi: Belirli bir LayoutObject öğesinin boyutunu ve konumunu hesaplarken artık bu nesneye köklenen alt ağacın dışına bakmıyoruz. Belirli bir nesnenin düzenini güncellemek için gereken tüm bilgiler önceden hesaplanır ve algoritmaya salt okunur giriş olarak sağlanır.
  • Daha önce, düzen algoritmasının tam olarak işlemediği uç durumlar vardı: Algoritmanın sonucu, önceki en son düzen güncellemesine bağlıydı. LayoutNG bu sorunları ortadan kaldırdı.

Ön boyama aşaması

Daha önce, resmi bir boyama öncesi oluşturma aşaması yoktu. Yalnızca düzen sonrası işlemlerden oluşan bir grup vardı. Ön boyama aşaması, düzen tamamlandıktan sonra düzen ağacının sistematik bir şekilde taranması olarak en iyi şekilde uygulanabilecek birkaç ilgili işlevin olduğu fark edildiğinde ortaya çıktı. En önemlileri şunlardır:

  • Boya geçersiz kılma işleminin yapılması: Eksik bilgilere sahip olduğumuzda, düzen sırasında boya geçersiz kılma işlemini doğru şekilde yapmak çok zordur. İki farklı sürece bölündüğünde doğru şekilde yapılması çok daha kolaydır ve çok verimli olabilir: Stil ve düzen sırasında içerik, basit bir boole işaretiyle "muhtemelen boya geçersiz kılınması gerekiyor" olarak işaretlenebilir. Boya öncesi ağaç yürüyüşü sırasında bu işaretleri kontrol eder ve gerekirse geçersiz kılma işlemi yaparız.
  • Boya mülkü ağaçları oluşturma: Daha sonra daha ayrıntılı olarak açıklanan bir işlemdir.
  • Piksele göre yakalanmış boya konumlarını hesaplama ve kaydetme: Kaydedilen sonuçlar, boya aşaması ve bunlara ihtiyaç duyan tüm aşağı akış kodları tarafından gereksiz hesaplama yapılmadan kullanılabilir.

Mülk ağaçları: Tutarlı geometri

Mülk ağaçları, web'de diğer tüm görsel efekt türlerinden farklı bir yapıya sahip olan kaydırma işleminin karmaşıklığıyla başa çıkmak için RenderingNG'nin başlarında kullanıma sunulmuştur. Mülk ağaçlarından önce Chromium'un derleyicisi, birleştirilmiş içeriğin geometrik ilişkisini temsil etmek için tek bir "katman" hiyerarşisi kullanıyordu. Ancak position:fixed gibi özelliklerin tüm karmaşıklıkları ortaya çıktıkça bu hiyerarşi hızla çöktü. Katman hiyerarşisi, bir katmanın "kaydırma üst öğesini" veya "klip üst öğesini" belirten ek yerel olmayan işaretçiler içerecek şekilde büyüdü ve kısa süre sonra kodun anlaşılması çok zorlaştı.

Mülk ağaçları, içeriğin taşma kaydırma ve kırpma özelliklerini diğer tüm görsel efektlerden ayrı olarak göstererek bu sorunu düzeltti. Bu sayede web sitelerinin gerçek görsel ve kaydırma yapısını doğru şekilde modellemek mümkün oldu. Ardından, "tek" yapmamız gereken, mülk ağaçlarının üzerine algoritmalar uygulamaktı (ör. birleştirilmiş katmanların ekran alanında dönüştürülmesi veya hangi katmanların kaydırıldığını, hangilerinin kaydırılmadığını belirleme).

Aslında kısa süre içinde, kodda benzer geometrik soruların ortaya çıktığı başka birçok yer olduğunu fark ettik. (Anahtar veri yapıları makalesinde daha kapsamlı bir liste bulabilirsiniz.) Bunların birkaçında, derleyici kodunun yaptığı aynı şeyin kopya uygulamaları vardı; hepsinin farklı bir hata alt kümesi vardı ve hiçbiri gerçek web sitesi yapısını düzgün bir şekilde modellememişti. Bu noktada çözüm netleşti: Tüm geometri algoritmalarını tek bir yerde merkezileştirin ve tüm kodu bu algoritmayı kullanacak şekilde yeniden yapılandırın.

Bu algoritmaların tümü de mülk ağaçlarına bağlıdır. Bu nedenle mülk ağaçları, RenderingNG'nin anahtar veri yapısıdır (yani ardışık düzen boyunca kullanılan bir veri yapısıdır). Bu nedenle, merkezi geometri kodu hedefine ulaşmak için mülk ağacı kavramını ardışık düzende çok daha erken bir aşamada (ön boyama aşamasında) tanıtmamız ve artık bu ağaçlardan yararlanan tüm API'leri, çalıştırılmadan önce ön boyama işleminin yapılmasını gerektirecek şekilde değiştirmemiz gerekiyordu.

Bu hikaye, BlinkNG yeniden düzenleme kalıbının bir başka yönüdür: Temel hesaplamaları tanımlayın, bunları kopyalamamak için yeniden düzenleyin ve bunları besleyen veri yapılarını oluşturan iyi tanımlanmış ardışık düzen aşamaları oluşturun. Mülk ağaçlarını tam olarak gerekli tüm bilgilerin mevcut olduğu noktada hesaplarız ve daha sonraki oluşturma aşamaları çalışırken mülk ağaçlarının değişememesini sağlarız.

Boya sonrası kompozisyon: Boya ve kompozisyonu ardışık düzene alma

Katman oluşturma, hangi DOM içeriğinin kendi birleştirilmiş katmanına (bu da bir GPU dokusunu temsil eder) yerleştirileceğini belirleme işlemidir. RenderingNG'den önce katmanlandırma, boyamadan sonra değil önce çalıştırılırdı (mevcut ardışık düzen için buraya bakın; sıra değişikliğine dikkat edin). Önce DOM'un hangi bölümlerinin hangi birleştirilmiş katmana gireceğine karar veririz ve yalnızca bundan sonra bu dokular için görüntü listeleri çizeriz. Doğal olarak, kararlar hangi DOM öğelerinin animasyonlu olduğu veya kaydırıldığı, 3D dönüşümlere sahip olduğu ve hangi öğelerin üzerine hangi öğelerin boyandığı gibi faktörlere bağlıydı.

Bu, kodda döngüsel bağımlılıkların olmasını gerektirdiği için büyük sorunlara yol açıyordu. Bu durum, oluşturma ardışık düzeni için büyük bir sorundur. Bunun nedenini bir örnek üzerinden görelim. Boyamayı geçersiz kılmamız gerektiğini varsayalım (yani, görüntü listesini yeniden çizmemiz ve ardından tekrar rasterleştirmemiz gerekir). Geçersiz kılma ihtiyacı, DOM'da veya stil ya da düzende yapılan bir değişiklikten kaynaklanabilir. Ancak elbette yalnızca gerçekten değişen bölümleri geçersiz kılmak isteriz. Bu, hangi birleştirilmiş katmanların etkilendiğini bulmak ve ardından bu katmanların görüntüleme listelerinin bir kısmını veya tamamını geçersiz kılmak anlamına geliyordu.

Bu, geçersiz kılma işleminin DOM, stil, düzen ve geçmiş katmanlandırma kararlarına (geçmiş: önceki oluşturulan çerçeve anlamına gelir) bağlı olduğu anlamına gelir. Ancak mevcut katmanlandırma da tüm bu faktörlere bağlıdır. Ayrıca, tüm katmanlandırma verilerinin iki kopyasına sahip olmadığımız için geçmiş ve gelecekteki katmanlandırma kararları arasındaki farkı anlamak zordu. Bu nedenle, döngüsel mantık içeren çok sayıda kod elde ettik. Bu durum, çok dikkatli olmadığımızda bazen mantıksız veya yanlış kodlara, hatta kilitlenmelere ya da güvenlik sorunlarına yol açıyordu.

Bu durumu ele almak için erken dönemde DisableCompositingQueryAsserts nesnesi kavramını kullanıma sunduk. Çoğu zaman, kod geçmiş katmanlandırma kararlarını sorgulamayı denediğinde bir iddia hatası oluşur ve hata ayıklama modundaysa tarayıcı kilitlenir. Bu sayede yeni hatalar oluşturmaktan kaçınabildik. Ayrıca, kodun geçmiş katmanlandırma kararlarını sorgulamasının meşru olduğu her durumda, bir DisableCompositingQueryAsserts nesnesi ayırarak buna izin verecek kod ekledik.

Planımız, zaman içinde tüm çağrı sitesi DisableCompositingQueryAssert nesnelerini kaldırmak ve ardından kodu güvenli ve doğru olarak beyan etmekti. Ancak katman oluşturma işlemi boyamadan önce gerçekleştiği sürece, çağrıların bir kısmının kaldırılmasının neredeyse imkansız olduğunu keşfettik. (Yakın zamanda bu sorunu giderebildik.) Bu, boya sonrası kompozisyon projesinde keşfedilen ilk nedendi. Bir işlem için iyi tanımlanmış bir ardışık düzen aşamanız olsa bile, ardışık düzende yanlış bir yerdeyse sonunda takılıp kalacağınızı öğrendik.

Boya Sonrası Birleştirme projesinin ikinci nedeni, Temel Birleştirme hatasıydı. Bu hatayı belirtmenin bir yolu, DOM öğelerinin web sayfası içerikleri için verimli veya eksiksiz bir katmanlandırma şemasının iyi bir 1:1 temsili olmamasıdır. Ayrıca, oluşturma işlemi boyamadan önce geldiğinden, daha çok görüntü listelerine veya özellik ağaçlarına değil, DOM öğelerine bağlıydı. Bu, mülk ağaçlarını kullanıma sunma nedenimize çok benzer. Mülk ağaçlarında olduğu gibi, doğru ardışık düzen aşamasını belirlerseniz, doğru zamanda çalıştırırsanız ve doğru temel veri yapılarını sağlarsanız çözüm doğrudan ortaya çıkar. Mülk ağaçlarında olduğu gibi, bu da boyama aşaması tamamlandıktan sonra çıktısının sonraki tüm ardışık düzen aşamalarında değiştirilemez olmasını garanti etmek için iyi bir fırsattı.

Avantajları

Gördüğünüz gibi, iyi tanımlanmış bir oluşturma ardışık düzeni uzun vadede çok büyük avantajlar sağlar. Düşündüğünüzden daha fazlası var:

  • Güvenilirlik büyük ölçüde artırıldı: Bu oldukça açık bir konudur. İyi tanımlanmış ve anlaşılır arayüzlere sahip daha temiz kodların anlaşılması, yazılması ve test edilmesi daha kolaydır. Bu sayede daha güvenilir olur. Ayrıca, daha az kilitlenme ve ücretsiz kullanımdan sonra ortaya çıkan daha az hata ile kodu daha güvenli ve daha kararlı hale getirir.
  • Genişletilmiş test kapsamı: BlinkNG sırasında paketimize çok sayıda yeni test ekledik. Dahili bileşenlerin odaklanmış şekilde doğrulanmasını sağlayan birim testleri, düzeltmiş olduğumuz eski hataları yeniden tanıtmamızı önleyen geriye dönük testler ve tüm tarayıcıların web standartlarına uygunluğu ölçmek için kullandığı, herkese açık ve ortaklaşa yönetilen Web Platformu Testi paketine eklenen birçok öğe bu kapsamdadır.
  • Genişletilmesi daha kolaydır: Bir sistem net bileşenlere ayrılmışsa mevcut bileşende ilerleme kaydetmek için diğer bileşenleri herhangi bir ayrıntı düzeyinde anlamak gerekmez. Bu sayede, herkes uzman olmak zorunda kalmadan oluşturma koduna değer katabilir ve sistemin tamamının davranışını daha kolay anlayabilir.
  • Performans: Makarna çorbası kodunda yazılmış algoritmaları optimize etmek yeterince zordur ancak bu tür bir ardışık düzen olmadan evrensel dişli kaydırma ve animasyonlar veya site izolasyonu için işlemler ve iş parçacıklar gibi daha da büyük şeyler elde etmek neredeyse imkansızdır. Paralellik, performansı büyük ölçüde artırmamıza yardımcı olabilir ancak aynı zamanda son derece karmaşıktır.
  • Verim ve sınırlama: BlinkNG sayesinde ardışık düzeni yeni ve farklı şekillerde kullanan birkaç yeni özellik vardır. Örneğin, oluşturma ardışık düzenini yalnızca bir bütçenin süresi dolana kadar çalıştırmak isteseydik ne olurdu? Yoksa şu anda kullanıcıyla alakalı olmadığı bilinen alt ağaçların oluşturulmasını atlayabilir miyim? content-visibility CSS özelliği, bunu sağlar. Bir bileşenin stilini düzenine göre ayarlama fikri ne dersiniz? Bunlar kapsayıcı sorguları.

Örnek olay: Kapsayıcı sorguları

Kapsayıcı sorguları, yakında kullanıma sunulacak ve merakla beklenen bir web platformu özelliğidir (CSS geliştiricileri tarafından yıllardır en çok istenen özelliktir). O kadar iyiyse neden henüz yok? Bunun nedeni, kapsayıcı sorgularının uygulanmasının stil ve düzen kodu arasındaki ilişkinin çok dikkatli bir şekilde anlaşılmasını ve kontrol edilmesini gerektirmesidir. Daha yakından inceleyelim.

Kapsayıcı sorgusu, bir öğe için geçerli olan stillerin bir üst öğenin düzenlenmiş boyutuna bağlı olmasına olanak tanır. Düzenlenen boyut, düzen sırasında hesaplandığından stil yeniden hesaplama işlemini düzenden sonra çalıştırmamız gerekir. Ancak stil yeniden hesaplama işlemi düzenden önce çalışır. Bu "tavuklar mı yumurtadan çıkar, yumurtalar mı tavuktan çıkar?" paradoksu, BlinkNG'den önce kapsayıcı sorgularını uygulayamamamızın tek nedenidir.

Bu sorunu nasıl çözebiliriz? Bu, geriye dönük bir ardışık düzen bağımlılığı değil mi? Yani boya sonrası birleştirme gibi projelerin çözdüğü aynı sorun değil mi? Daha da kötüsü, yeni stiller üst öğenin boyutunu değiştirirse ne olur? Bu bazen sonsuz bir döngüye neden olmaz mı?

Döngüsel bağımlılık, prensipte contain CSS özelliği kullanılarak çözülebilir. Bu özellik, bir öğenin dışındaki oluşturmanın bu öğenin alt ağacındaki oluşturmaya bağlı olmamasına olanak tanır. Bu, kapsayıcı sorguları kapsayıcılık gerektirdiği için kapsayıcı tarafından uygulanan yeni stillerin kapsayıcının boyutunu etkileyemeyeceği anlamına gelir.

Ancak bu yeterli değildi ve boyut sınırlamasından daha zayıf bir sınırlama türü sunmak gerekiyordu. Bunun nedeni, bir kapsayıcı sorguları kapsayıcısının satır içi boyutlarına göre yalnızca tek bir yönde (genellikle blok) yeniden boyutlandırılabilmesinin yaygın olarak istenmesidir. Bu nedenle, satır içi boyut sınırlama kavramı eklendi. Ancak bu bölümdeki çok uzun nottan da görebileceğiniz gibi, satır içi boyut sınırlamanın mümkün olup olmadığı uzun süre boyunca net değildi.

Kapsayıcılık özelliğini soyut spesifikasyon dilinde açıklamak ile doğru şekilde uygulamak arasında fark vardır. BlinkNG'nin hedeflerinden birinin, oluşturmanın ana mantığını oluşturan ağaç yürüyüşlerine kapsayıcılık ilkesini getirmek olduğunu hatırlayın: Bir alt ağaçta gezinirken alt ağacın dışından bilgi gerekmemelidir. Görüntüleme kodu, kapsayıcılığa uyuyorsa CSS kapsayıcılığını uygulamak çok daha temiz ve kolaydır.

Gelecek: Ana iş parçacığı dışındaki oluşturma ve daha fazlası

Burada gösterilen oluşturma ardışık düzeni, mevcut RenderingNG uygulamasından biraz daha ileridedir. Katmanlandırmanın ana iş parçacığında olmadığı gösteriliyor ancak şu anda ana iş parçacığında. Ancak boya sonrası birleştirme özelliği kullanıma sunulduğu ve katman oluşturma işlemi boya sonrasına taşındığı için bu işlemin yapılması an meselesi.

Bunun neden önemli olduğunu ve nerelere yol açabileceğini anlamak için oluşturma motorunun mimarisini biraz daha yüksek bir bakış açısından değerlendirmemiz gerekir. Chromium'un performansını iyileştirmenin önündeki en kalıcı engellerden biri, oluşturma aracının ana iş parçacığının hem ana uygulama mantığını (yani çalışan komut dosyasını) hem de oluşturmanın büyük kısmını ele almasıdır. Sonuç olarak, ana iş parçacığı sık sık iş yüküyle dolup taşar ve ana iş parçacığı tıkanıklığı, genellikle tüm tarayıcıda darboğaz olur.

Ancak bu böyle olmak zorunda değil. Chromium'un mimarisinin bu yönü, tek iş parçacıklı yürütmenin baskın programlama modeli olduğu KHTML günlerinden kalmadır. Tüketici sınıfı cihazlarda çok çekirdekli işlemciler yaygınlaştığında, tek iş parçacıklı varsayımı Blink'e (eski adıyla WebKit) tamamen yerleştirilmişti. Uzun zamandır oluşturma motoruna daha fazla iş parçacığı eklemek istiyorduk ancak eski sistemde bu mümkün değildi. Yeniden oluşturma NG'nin ana hedeflerinden biri, bu durumdan kurtulmak ve oluşturma işlemini kısmen veya tamamen başka bir iş parçacığına (veya iş parçacılarına) taşımayı mümkün kılmaktır.

BlinkNG tamamlanmak üzere olduğundan bu alanı keşfetmeye başladık. Engellemesiz Taahhüt, oluşturma aracının iş parçacığı modelini değiştirmeye yönelik ilk girişimdir. Oluşturucu commit'i (veya yalnızca commit), ana iş parçacığı ile oluşturucu iş parçacığı arasındaki bir senkronizasyon adımıdır. Taahhüt sırasında, ana iş parçacığında üretilen oluşturma verilerinin kopyalarını oluştururuz. Bu kopyalar, oluşturucu iş parçacığında çalışan yayın sonrası oluşturma kodu tarafından kullanılır. Bu senkronizasyon gerçekleşirken, ana iş parçacığı yürütme durdurulur ve kopyalama kodu, oluşturucu iş parçacığında çalışır. Bu, ana iş parçacığı, oluşturucu iş parçacığı tarafından kopyalanırken oluşturma verilerini değiştirmesin diye yapılır.

Engellemesiz Taahhüt, ana iş parçacığının durması ve taahhüt aşamasının sona ermesini beklemesi ihtiyacını ortadan kaldırır. Ana iş parçacığı, taahhüt işlemi oluşturucu iş parçacığında eşzamanlı olarak çalışırken çalışmaya devam eder. Engellemesiz Taahhüt'ün net etkisi, ana iş parçacığında oluşturma işlemine ayrılan sürenin azaltılması olacaktır. Bu da ana iş parçacığındaki tıkanıklığı azaltır ve performansı artırır. Bu makalenin yazıldığı tarihte (Mart 2022) Engellemeyen Taahhüt'ün çalışan bir prototipi var ve bu özelliğin performans üzerindeki etkisini ayrıntılı bir şekilde analiz etmeye hazırlanıyoruz.

Ana iş parçacığı dışındaki oluşturma, katmanlandırmayı ana iş parçacığının dışına ve bir çalışan iş parçacığına taşıyarak oluşturma motorunun görselle eşleşmesini sağlama amacıyla geliştirilmektedir. Engellemesiz Taahhüt gibi bu işlem de oluşturma iş yükünü azaltarak ana iş parçacığındaki tıkanıklığı azaltır. Bu tür bir proje, boya sonrası kompozisyondaki mimari iyileştirmeler olmadan asla mümkün olmazdı.

Ayrıca, planlama aşamasında olan daha fazla projemiz var. Sonunda, oluşturma işini yeniden dağıtmayı denemeyi mümkün kılan bir temele sahip olduk ve neler yapabileceğimizi görmek için çok heyecanlıyız.