Blink, Chromium'un web platformunu uygulamasını ifade eder ve birleştirmeden önceki oluşturma işleminin tüm aşamalarını kapsar ve birleştirici kaydetmeyle sona erer. Bu serideki önceki bir makalede yanıp sönen ışık oluşturma mimarisi hakkında daha fazla bilgi edinebilirsiniz.
Blink, hayatına WebKit'in çatalı olarak başladı. WebKit, 1998'de KHTML'nin çatalı. Chromium'daki en eski (ve en önemli) kodlardan bazılarını içerir ve 2014'e kadar kesinlikle eskiliğini gösterir. O yıl, BlinkNG adını verdiğimiz bayrağı altında bir dizi iddialı projeye başladık. Amacımız, Blink kodunun organizasyonu ve yapısında uzun süredir var olan eksiklikleri gidermekti. Bu makalede, BlinkNG ve onun kurucu projeleri ele alınmaktadır: Bu projeleri neden yaptığımız, neler başardıkları, tasarımlarını şekillendiren yol gösterici ilkeler ve gelecekte sunabilecekleri iyileştirmeler.
NG öncesi oluşturma
Blink'teki oluşturma ardışık düzeni, kavramsal olarak her zaman aşamalara (stil, layout, boya vb.) bölünüyordu. Ancak soyutlamadaki engeller sızdırıyordu. Genel olarak, oluşturma ile ilişkili veriler uzun ömürlü, değişebilir nesnelerden oluşuyordu. Bu nesneler herhangi bir zamanda değiştirilebilir, ayrıca art arda oluşturma güncellemeleri tarafından sıklıkla geri dönüştürülüp yeniden kullanılmıştır. Şu gibi basit soruları güvenilir bir şekilde yanıtlamak imkansızdı:
- Stil, düzen veya boyama çıktısının güncellenmesi gerekiyor mu?
- Bu veriler ne zaman "nihai" hale gelecek değer nedir?
- Bu veriler ne zaman düzenlenebilir?
- Bu nesne ne zaman silinecek?
Bu durumun birçok örneği vardır. Örneğin:
Style, stil sayfalarını temel alarak ComputedStyle
oluşturur; ancak ComputedStyle
sabit değildi; bazı durumlarda ardışık düzen aşamaları tarafından değiştirilir.
Stil, bir LayoutObject
ağacı oluşturur, ardından düzen bu nesnelere boyut ve konumlandırma bilgilerini ekler. Bazı durumlarda, düzen ağaç yapısını bile değiştirir. Düzenin giriş ve çıkışları arasında net bir ayrım yoktur.
Style, birleştirmenin sürecini belirleyen aksesuar veri yapıları oluşturur ve bu veri yapıları, style ifadesinden sonraki her aşamada yerinde değiştirilir.
Daha düşük bir düzeyde, oluşturma veri türleri çoğunlukla özel ağaçlardan oluşur (örneğin, DOM ağacı, stil ağacı, düzen ağacı, boyama özelliği ağacı). ve oluşturma aşamaları, yinelemeli ağaç yürüyüşleri olarak uygulanır. İdeal olarak, bir ağaç yürüyüşü içerir: Belirli bir ağaç düğümünü işlerken o düğümde bulunan alt ağacın dışındaki hiçbir bilgiye erişmememiz gerekir. Bu, RenderingNG öncesinde hiçbir zaman doğru değildi; ağaç yürüyüşleri, işlenen düğümün üst öğelerinden sıklıkla erişilen bilgilere erişim sağlar. Bu da sistemi son derece kırılgan ve hataya açık hale getirdi. Ayrıca ağacın kökü dışındaki bir yerden ağaç yürüyüşüne başlamak da mümkün değildi.
Son olarak, kod boyunca, oluşturma ardışık düzeninde birçok giriş olduğu görülüyor: 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 maruz kalan özel API'ler. Hatta oluşturma ardışık düzeninde birkaç yinelemeli ve geriye kalan yol vardı (yani bir aşamanın başlangıcından bir diğerinin başlangıcına atlama). Bu erişim noktalarının her birinin kendine özgü davranışı vardır ve bazı durumlarda oluşturma işleminin sonucu, oluşturma güncellemesinin tetiklenme şekline göre değişir.
Neleri değiştirdik?
BlinkNG, büyük ve küçük birçok alt projeden oluşur. Bu projelerin ortak amacı, daha önce açıklanan mimari kusurları ortadan kaldırmaktır. Bu projelerde, görüntü oluşturma ardışık düzenini gerçek bir ardışık düzene dönüştürmek için tasarlanmış birkaç yol gösterici ilke bulunur:
- Tek tip giriş noktası: Ardışık düzene her zaman en baştan girmemiz gerekir.
- İşlevsel aşamalar: Her aşamanın iyi tanımlanmış giriş ve çıkışları olmalı, ayrıca aşamalar işlevsel, yani belirleyici ve tekrarlanabilir olmalı, çıkışlar ise yalnızca tanımlanan girişlere bağlı olmalıdır.
- Sabit girişler: Herhangi bir aşamanın girişleri, sahne çalışırken etkili bir şekilde sabit olmalıdır.
- Sabit çıkışlar: Bir aşama tamamlandıktan sonra, oluşturma güncellemesinin geri kalanı boyunca sahnenin çıkışları sabit olmalıdır.
- Kontrol noktası tutarlılığı: Her aşamanın sonunda, o ana kadar üretilen oluşturma verileri kendi arasında tutarlı olmalıdır.
- İşe tekilleştirme: Her şeyi yalnızca bir kez hesaplayın.
BlinkNG alt projelerinin tam listesi okumayı yorabilir, ancak aşağıda verilen bazı sonuçlar belirtilmiştir.
Doküman yaşam döngüsü
DocumentLifecycle sınıfı, oluşturma ardışık düzenindeki ilerlememizi takip eder. Daha önce listelenen değişmez değerleri zorunlu kılan aşağıdaki gibi temel kontrolleri gerçekleştirmemizi sağlar:
- Bir ComputedStyle özelliğinde değişiklik yapıyorsak belge yaşam döngüsü
kInStyleRecalc
olmalıdır. - DocumentLifecycle durumu
kStyleClean
veya sonrasıysaNeedsStyleRecalc()
, ekli herhangi bir düğüm için false değerini döndürmelidir. - paint yaşam döngüsü aşamasına girerken yaşam döngüsü durumu
kPrePaintClean
olmalıdır.
BlinkNG'yi uygulama süreci boyunca, bu değişmez değerleri ihlal eden kod yollarını sistematik olarak kaldırdık ve regresyona girmediğimizden emin olmak için koda çok daha fazla onaylama yerleştirdik.
Biraz tavşan deliğinden geçip düşük seviye oluşturma koduna bakarsanız kendinize "Buraya nasıl geldim?" diye sorabilirsiniz. Daha önce belirtildiği gibi, oluşturma ardışık düzenine çeşitli giriş noktaları vardır. Daha önce, yinelemeli ve aktaran çağrı yolları ile ardışık düzene baştan başlamak yerine ara aşamada girdiğimiz yerler bu kapsama giriyordu. BlinkNG sürecinde bu arama yollarını analiz ettik ve tümünün iki temel senaryoya indirgenebilir olduğunu belirledik:
- Tüm oluşturma verilerinin güncellenmesi gerekir. Örneğin, görüntüleme için yeni pikseller oluştururken veya etkinlik hedefleme için isabet testi yaparken.
- Belirli bir sorgu için, tüm oluşturma verilerini güncellemeden yanıtlanabilecek güncel bir değere ihtiyacımız vardır. Buna
node.offsetTop
gibi çoğu JavaScript sorgusu dahildir.
Artık oluşturma ardışık düzenine bu iki senaryoya karşılık gelen yalnızca iki giriş noktası bulunuyor. Kalan kod yolları kaldırıldı veya yeniden düzenlendi ve artık ara aşamadan başlayarak ardışık düzene girilemez. Bu sayede, oluşturma güncellemelerinin tam olarak ne zaman ve nasıl gerçekleştiğiyle ilgili birçok gizemi ortadan kaldırarak sistem davranışı hakkında akıl yürütmeyi çok daha kolay bir hale getirdik.
Ardışık düzen stili, düzeni ve ön boyama
Boya işleminden önceki oluşturma aşamaları toplu olarak aşağıdakilerden sorumludur:
- DOM düğümlerinin nihai stil özelliklerini hesaplamak için stili basamaklama algoritmasını çalıştırma.
- Dokümanın kutu hiyerarşisini temsil eden düzen ağacı oluşturma.
- Tüm kutular için boyut ve konum bilgileri belirleniyor.
- Boyama için piksel alt geometrisini tüm piksel sınırlarına yuvarlama veya tutturma.
- Birleştirilmiş katmanların özelliklerini belirleme (afin dönüşüm, filtreler, opaklık veya GPU hızlandırmalı olabilecek herhangi bir şey).
- Önceki boyama aşamasından bu yana hangi içeriklerin değiştiğini ve boyanması ya da yeniden boyanması (boyanın geçersiz kılınması) gerektiğini belirleme.
Bu liste değişmedi, ancak BlinkNG öncesinde bu işin büyük kısmı geçici olarak, birden fazla oluşturma aşamasına yayılmış, birçok yinelenen işlev ve yerleşik verimsizliklerle gerçekleştiriliyordu. Örneğin, her zaman düğümlerin nihai stil özelliklerinin hesaplanmasından her zaman style (stil) aşaması sorumlu olmuştur. Ancak, style (stil) aşaması tamamlanana kadar nihai stil özelliği değerlerini belirlemediğimiz birkaç özel durum olmuştur. Oluşturma sürecinde, stil bilgilerinin eksiksiz ve değiştirilemez olduğunu kesin olarak söyleyebileceğimiz resmî veya uygulanabilir bir nokta yoktu.
BlinkNG öncesi sorunun iyi bir örneği boyanın geçersiz kılınmasıdır. Daha önce, boyanın geçersiz kılınması boyaya kadarki tüm oluşturma aşamalarına yayılmıştı. Stil veya düzen kodunda değişiklik yapılırken boya geçersiz kılma mantığında hangi değişikliklerin yapılması gerektiğini bilmek zordu. Ayrıca, gereğinden az veya fazla geçersiz kılınan hatalara yol açan bir hata yapmak da kolaydı. LayoutNG konulu bu serideki makalede eski boya geçersiz kılma sisteminin incelikleri hakkında daha fazla bilgi edinebilirsiniz.
Boyama için alt piksel düzeni geometrisini tüm piksel sınırlarına tutturmak, aynı işlevin birden fazla uygulamasına sahip olduğumuz ve birçok yedek iş yaptığımıza dair bir örnektir. Boyama sistemi tarafından kullanılan bir tane piksel tutturma kod yolu vardı. Ayrıca, boyama kodunun dışında piksel yapılı koordinatların tek seferlik, anında hesaplanması gerektiğinde tamamen ayrı bir kod yolu kullanılıyordu. Elbette her uygulamanın kendi hataları vardı ve sonuçları her zaman eşleşmedi. Bu bilgiler önbelleğe alınmadığından, sistem bazen aynı hesaplamayı tekrar tekrar yapıyordu. Bu da performansta bir zorluk oluşturuyordu.
Boya öncesi işleme aşamalarındaki mimari eksiklikleri ortadan kaldıran bazı önemli projeleri burada bulabilirsiniz.
Project Squad: Stil aşamasını planlama
Bu projede stil aşamasındaki iki temel sorunun üstesinden gelmeyi başardık ve bu da projeyi düzgün bir şekilde düzenlememizi önledi:
Stil aşamasının iki ana çıkışı vardır: ComputedStyle
. Bu çıktılar, CSS basamaklama algoritmasının DOM ağacı üzerinde çalıştırılmasının sonucunu içerir; ve düzen aşaması için işlem sırasını belirleyen LayoutObjects
ağacı. Kavramsal olarak, basamak algoritmasının çalıştırılması, kesin olarak düzen ağacı oluşturulmadan önce gerçekleştirilmelidir. Ancak daha önce bu iki işlem aralıklı olarak yapılıyordu. Project Squad bu ikisini birbirinden farklı, ardışık aşamalara bölmeyi başardı.
Daha önce ComputedStyle
, stil yeniden hesaplama sırasında her zaman nihai değerini alamıyordu. ComputedStyle
ürününün daha sonraki bir ardışık düzen aşamasında güncellendiği birkaç durum söz konusudur. Project Squad bu kod yollarını başarıyla yeniden düzenledi. Böylece ComputedStyle
, stil aşamasından sonra hiçbir zaman değiştirilmez.
LayoutNG: Düzen aşamasının ardışık düzenini oluşturma
RenderingNG'nin temel taşlarından biri olan bu anı proje, düzen oluşturma aşamasının baştan sona yeniden yazılmış bir haliydi. Burada projenin tamamının adaletini sağlamayacağız, ancak genel BlinkNG projesinin dikkat çeken birkaç yönü vardır:
- Daha önce, düzen aşamasında stil aşamasında oluşturulan bir
LayoutObject
ağacı alınıyordu ve ağaç, boyut ve konum bilgileriyle açıklanıyordu. Bu nedenle, girişler ile çıkışlar arasında net bir ayrım yapılmamıştır. LayoutNG, düzenin birincil, salt okunur çıktısı olan ve sonraki oluşturma aşamaları için birincil girdi olarak görev yapan parça ağacını kullanıma sundu. - LayoutNG, sınırlama özelliğini düzene getirdi: Belirli bir
LayoutObject
öğesinin boyutu ve konumu hesaplanırken artık kökü bu nesneye dayanan 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 bir giriş olarak sağlanır. - Daha önce, düzen algoritmasının tam olarak işlevsel olmadığı uç durumlar vardı: Algoritmanın sonucu, önceki en son düzen güncellemesine bağlıydı. LayoutNG, bu durumları ortadan kaldırdı.
Boya öncesi aşaması
Önceden boyama öncesi resmî bir görüntü oluşturma aşaması yoktu. Yalnızca düzen sonrası birkaç işlem yapılıyordu. Boya öncesi aşaması, düzen tamamlandıktan sonra düzen ağacında sistematik bir geçiş olarak en iyi şekilde uygulanabilecek birkaç ilgili işlevin olduğunun kabul edilmesiyle ortaya çıktı; en önemlisi:
- Boya geçersiz kılma işlemleri: Eksik bilgi olduğunda, düzen sırasında boyama geçersiz kılma işlemini doğru bir şekilde yapmak çok zordur. Doğru şekilde yapılması çok daha kolaydır ve iki farklı sürece bölündüğünde çok verimli olabilir: stil ve düzen sırasında içerik, "muhtemelen boyamanın geçersiz kılınması gerekiyor" şeklinde basit bir boole işaretiyle işaretlenebilir. Boya öncesi yürüyüş sırasında bu işaretleri kontrol edip gerektiğinde geçersiz kılma işlemleri yaparız.
- Boya özelliği ağaçları oluşturma: Daha ayrıntılı olarak açıklanan bir süreç.
- Piksel yakalamalı boya konumlarını hesaplama ve kaydetme: Kaydedilen sonuçlar, gereksiz hesaplamaya gerek kalmadan hem boya aşamasında hem de bunlara ihtiyacı olan aşağı akış kodları tarafından kullanılabilir.
Mülk ağaçları: Tutarlı geometri
Özellik ağaçları, web'deki 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. Özellik ağaçlarından önce Chromium'un birleştiricisi tek bir "katman" kullandı hiyerarşisini kullanarak birleştirilmiş içeriğin geometrik ilişkisini temsil eder, ancak pozisyon:sabit gibi özelliklerin tüm karmaşıklıkları görünür hale geldikçe bu durum hızla ayrılıyor. Katman hiyerarşisinde, "kaydırma üst öğesi"ni gösteren yerel olmayan daha fazla işaretçi artırıldı veya "klip üst" ve çok geçmeden kodu anlamak çok zordu.
Mülk ağaçları, içeriğin taşma kaydırma ve klip özelliklerini diğer tüm görsel efektlerden ayrı göstererek bu durumu düzeltti. Bu da web sitelerinin gerçek görsel ve kaydırma yapısının doğru bir şekilde modellenmesini mümkün kıldı. Sonra, "tümü" mülk ağaçlarının üzerine, birleştirilmiş katmanların ekran-uzak dönüşümü veya hangi katmanların kaydırılıp hangilerinin kaydırılmadığını belirlemek gibi algoritmalar uygulamak zorundaydık.
Hatta kısa süre içinde, kodda benzer geometrik soruların sorulduğu birçok başka yer olduğunu fark ettik. (Temel veri yapıları gönderisinde daha kapsamlı bir liste bulabilirsiniz.) Bunlardan birkaçı, birleştirici kodun yaptığı aynı şeyi tekrar tekrar uygulamaktadır. hata alt kümesi farklıydı; hiçbirinin gerçek web sitesi yapısı düzgün şekilde modellenmemiş olması gerekir. Daha sonra çözüm anlaşılır hale geldi: Tüm geometri algoritmalarını tek bir yerde toplayın ve kodu kullanmak için tüm kodu yeniden düzenleyin.
Bu algoritmaların tümü özellik ağaçlarını temel alır. Bu nedenle özellik ağaçları, RenderingNG'nin ardışık düzeninde kullanılan bir temel veri yapısıdır. Dolayısıyla, bu merkezi geometrik kod hedefine ulaşmak için özellik ağaçları kavramını ardışık düzenin çok daha önceki aşamalarında (ön boyamada) kullanıma sunmamız ve artık bu ağaçlara bağlı olan tüm API'leri, çalıştırılmadan önce ön boyanın çalıştırı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: önemli hesaplamaları tanımlama, bunların yinelenmesini önlemek için yeniden düzenleme ve bunları besleyen veri yapılarını oluşturan iyi tanımlanmış ardışık düzen aşamaları oluşturma. Mülk ağaçlarını tam olarak gerekli tüm bilgilerin mevcut olduğu anda hesaplarız; Sonraki oluşturma aşamaları çalışırken mülk ağaçlarının değişmemesini sağlıyoruz.
Boya sonrası kompozit: Ardışık düzen boyama ve birleştirme
Katmanlaştırma, hangi DOM içeriğinin kendi birleştirilmiş katmanına gireceğini (yani bir GPU dokusunu temsil eder) bulma işlemidir. RenderingNG'den önce, katmanlama boyama işleminden sonra değil, önce çalıştırıldı (mevcut ardışık düzen için buraya bakın; sıra değişikliğine dikkat edin). İlk olarak DOM'nin hangi bölümlerinin hangi birleştirilmiş katmana gideceğine karar verir ve ardından bu dokular için görüntüleme listeleri çizeriz. Doğal olarak kararlar, hangi DOM öğelerinin animasyon ya da kaydırma yaptığı, 3D dönüşümlerine sahip olduğu ve hangi öğelerin üzerine boyandığı gibi faktörlere bağlıydı.
Bu durum büyük sorunlara yol açtı. Bunun nedeni, kodda az ya da çok döngüsel bağımlılıklar bulunmasıydı. Döngüsel bağımlılıklar, oluşturma ardışık düzeni açısından büyük bir sorundu. Bir örnek üzerinden bunun nedenini görelim. Boyayı geçersiz kılmamız gerektiğini (yani görüntüleme listesini yeniden çizmemiz ve ardından tekrar kafeslememiz gerektiğini) varsayalım. Geçersiz kılma işlemi, DOM'deki bir değişiklikten ya da değiştirilmiş bir stil veya düzenden kaynaklanabilir. Ancak tabii ki yalnızca gerçekten değişen bölümleri geçersiz kılmak istiyoruz. Bu da hangi birleştirilmiş katmanların etkilendiğinin bulunması ve ardından bu katmanlara ait görüntüleme listelerinin bir kısmını veya tamamını geçersiz kılması anlamına geliyordu.
Bu durum, geçersiz kılma işleminin DOM, stil, düzen ve geçmiş katmanlaştırma kararlarına bağlı olduğu anlamına gelir (geçmiş: daha önce oluşturulan karenin anlamı). Ancak mevcut katmanlaştırma, tüm bunlara bağlı. Elimizde tüm katmanlaştırma verilerinin iki kopyası olmadığı için, geçmiş ve gelecekteki katmanlaştırma kararları arasındaki farkı ayırt etmek zordu. Böylece, döngüsel akıl yürütmeye sahip çok sayıda kodla karşılaştık. Bu durum bazen mantıksız veya yanlış kodlara, hatta çok dikkatli olmamamız halinde kilitlenmelere ya da güvenlik sorunlarına yol açıyordu.
Bu durumla başa çıkmak için başlangıçta DisableCompositingQueryAsserts
nesnesi kavramını ortaya koymuştuk. Kod çoğu zaman geçmiş katmanlaştırma kararlarını sorgulamaya çalışırsa onaylama hatasına neden olur ve hata ayıklama modundaysa tarayıcının kilitlenmesine neden olur. Bu sayede yeni hatalar oluşmaz. Geçmişteki katmanlaştırma kararlarını sorgulamak için meşru olarak gereken kodun gerektiği her durumda, bir DisableCompositingQueryAsserts
nesnesi ayırarak koda izin vermek amacıyla kod ekleriz.
Planımız zaman içinde çağrı sitelerindeki tüm DisableCompositingQueryAssert
nesnelerini kaldırıp kodun güvenli ve doğru olduğunu bildirmekti. Ancak, boyama işleminden önce katmanlaştırma olduğu sürece bazı çağrıların kaldırılmasının imkansız olduğunu keşfettik. (Sonunda bunu çok kısa bir süre önce kaldırabildik!) Composite After Paint projesinin keşfedilmesinin ilk nedeni buydu. Öğrendiklerimize göre, bir işlem için iyi tanımlanmış bir ardışık düzen aşamasınız olsa bile, ardışık düzende yanlış yerde olursa sonunda takılıp kalabilirsiniz.
Boyama Sonrası Kompozit projesinin ikinci nedeni, Temel Birleştirme hatasıydı. Bu hatayı ifade etmenin bir yolu, DOM öğelerinin web sayfası içerikleri için verimli veya eksiksiz bir katmanlaştırma şemasını iyi bir 1:1 temsil etmemesidir. Ayrıca birleştirme işlemi boyamadan önce gerçekleştiği için doğal olarak görüntüleme listelerine veya özellik ağaçlarına değil, DOM öğelerine bağlıydı. Bu, mülk ağaçlarını kullanıma sunmamızın nedenine çok benziyor. Mülk ağaçlarında olduğu gibi, doğru ardışık düzen aşamasını belirlediğinizde, doğru zamanda çalıştırırsanız ve ona doğru temel veri yapılarını sağlarsanız çözüm de doğrudan işe yarar. Mülk ağaçlarında olduğu gibi bu durum, boyama aşaması tamamlandıktan sonra çıktısının sonraki tüm boru hattı aşamaları için değişmez olmasını garantilemek açısından iyi bir fırsattı.
Avantajları
Gördüğünüz gibi iyi tanımlanmış bir oluşturma ardışık düzeni, uzun vadede büyük faydalar sağlar. Tahmin edebileceğinizden daha fazlası var:
- Güvenilirliği büyük ölçüde iyileştirdi: Bu yöntem oldukça basittir. İ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 da onu daha güvenilir kılıyor. Ayrıca, daha az sayıda kilitlenme ve ücretsiz sonrasında daha az kullanım hatası ile kodu daha güvenli ve kararlı hale getirir.
- Genişletilmiş test kapsamı: BlinkNG süresince, paketimize çok sayıda yeni test ekledik. Buna, dahili öğelerin odaklı şekilde doğrulanmasını sağlayan birim testleri de dahildir. düzelttiğimiz (çok fazla!) eski hataları tekrar getirmemizi engelleyen regresyon testleri; ve tüm tarayıcıların web standartlarına uygunluğu ölçmek için kullandığı, toplu olarak sağlanmış Web Platformu Test paketi'ni kullanıma sunduk.
- Genişletmesi daha kolay: Bir sistem net bileşenlere bölünmüşse mevcut sistemde ilerleme kaydetmek için diğer bileşenleri ne kadar ayrıntılı olursa olsun anlamak gerekmez. Bu, herkesin kapsamlı bir uzman olmak zorunda kalmadan oluşturma koduna değer eklemesini kolaylaştırır ve tüm sistemin davranışı hakkında akıl yürütmeyi kolaylaştırır.
- Performans: Spagetti koduyla yazılan algoritmaları optimize etmek yeterince zordur ancak böyle bir ardışık düzen olmadan evrensel mesaj dizili kaydırma ve animasyonlar veya site izolasyonu için işlemler ve iş parçacıkları gibi daha büyük hedeflere ulaşmak neredeyse imkansızdır. Paralellik, performansı önemli ölçüde artırmamıza yardımcı olabilir ancak bir yandan da son derece karmaşıktır.
- Gelişme ve kontrol altına alma: BlinkNG tarafından sağlanan, ardışık düzende yeni ve yeni yollarla çalışan çeşitli yeni özellikler vardır. Örneğin, oluşturma ardışık düzenini yalnızca bütçe süresi dolana kadar çalıştırmak istersek ne olur? Yoksa şu anda kullanıcıyla alakalı olmadığı bilinen alt ağaçlar için oluşturma işlemini atlamak mı istiyorsunuz? content- visibility CSS özelliği bunu etkinleştirir. Bir bileşenin stilinin düzenine bağlı olmasını nasıl sağlayabilirim? Bu, kapsayıcı sorguları'dır.
Örnek olay: Kapsayıcı sorguları
Kapsayıcı sorguları, yakında kullanıma sunulacak web platformu özelliklerinden biridir. Bu özellik, yıllardır CSS geliştiricilerinden en çok talep gören özelliklerden biridir. Bu kadar güzel bir şeyse 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. Biraz ayrıntılarına inelim.
Kapsayıcı sorgusu, bir öğeye uygulanan stillerin, bir üst öğenin yerleştirilmiş boyutuna bağlı olmasına olanak tanır. Düzenlenen boyut düzen sırasında hesaplandığından, düzenden sonra stil yeniden hesaplamayı çalıştırmamız gerekir. ancak stil yeniden hesaplama düzenden önce çalışır! Bu tavuk-yumurta paradoksu, BlinkNG'den önce kapsayıcı sorgularını uygulayamamamızın tek nedenidir.
Bu sorunu nasıl çözebiliriz? Geriye dönük ardışık düzen bağımlılığı, yani Kompozit After Paint çözülmüş gibi projelerdeki problemle aynı 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 yol açmaz mı?
Döngüsel bağımlılık prensip olarak, bir öğenin dışında oluşturma işleminin öğenin alt ağacının içinde oluşturulmasına bağlı olmama sağlayan CSS'yi içer özelliğinin kullanılmasıyla çözülebilir. Başka bir deyişle, kapsayıcı sorguları içerme gerektirdiğinden, kapsayıcı tarafından uygulanan yeni stiller kapsayıcının boyutunu etkileyemez.
Ama aslında bu yeterli değildi ve yalnızca bedeni kontrol altına almaktan ziyade daha zayıf bir kapsam türünün eklenmesi gerekiyordu. Bunun nedeni, bir kapsayıcı sorguları kapsayıcısının satır içi boyutlarına göre yalnızca tek yönde (genellikle blok) yeniden boyutlandırabilmesini istemesidir. Dolayısıyla satır içi boyut kapsama kavramı eklenmiştir. 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 zamandır anlaşılmıyordu.
Kapsamı soyut spesifikasyon dilinde tanımlamak bir şey, doğru şekilde uygulamak ise bambaşka bir şey. BlinkNG'nin hedeflerinden birinin, içerme ilkesini, oluşturma işleminin ana mantığını oluşturan ağaç yürüyüşlerine taşımak olduğunu hatırlayın: Bir alt ağacın içinden geçerken, alt ağacın dışından hiçbir bilgi gerekmemelidir. Gerektiğinde (elbette bu bir kaza değildi) oluşturma kodu kapsayıcı ilkesine uygunsa CSS'nin kapsamı çok daha temiz ve daha kolay şekilde uygulanabilir.
Gelecek: ana olmayan iş parçacığı birleştirme ... ve ötesi!
Burada gösterilen oluşturma ardışık düzeni, aslında mevcut RenderingNG uygulamasının biraz ilerisindedir. Katmanlaştırma, ana iş parçacığının dışında olduğu halde şu anda hâlâ ana iş parçacığında bulunuyor. Bununla birlikte, bu işlemin tamamlanması yalnızca bir zaman meselesidir. Artık Kompozit Boya sonrası Boya gönderildi ve katmanlandırma, boyama işleminden sonra tamamlandı.
Bunun neden önemli olduğunu ve başka hangi noktalara yol açabileceğini anlamak için, oluşturma motorunun mimarisini biraz daha yüksek bir bakış açısıyla düşünmemiz gerekir. Chromium'un performansını iyileştirmenin önündeki en uzun ömürlü engellerden biri, oluşturucunun ana iş parçacığının hem ana uygulama mantığını (yani komut dosyasını çalıştırma) hem de oluşturma işlemini toplu olarak halletmesidir. Sonuç olarak, ana iş parçacığı genellikle işle doygun hale gelir ve ana iş parçacığı tıkanıklığı, çoğu zaman tarayıcının tamamındaki performans sorunudur.
Neyse ki bu şekilde olmak zorunda değilsiniz. Chromium'un mimarisinin bu yönü, tek iş parçacıklı yürütmenin baskın programlama modeli olduğu KHTML günlerine kadar dayanır. Tüketici sınıfı cihazlarda çok çekirdekli işlemciler yaygınlaştığında, tek iş parçacıklı varsayımı tamamen Blink (eski adıyla WebKit) üzerinde işlenmişti. Oluşturma motoruna uzun süredir daha fazla iş parçacığı eklemek istiyorduk. Ancak bu, eski sistemde mümkün değildi. Oluşturma NG'sinin ana hedeflerinden biri, kendimizi bu delikten kazıp çıkarmak ve oluşturma işini kısmen ya da tamamen başka bir iş parçacığına (veya iş parçacıklarına) taşımayı mümkün kılmaktı.
BlinkNG tamamlanmak üzere olduğuna göre, bu alanı keşfetmeye çoktan başladık. Engelleme Dışı Taahhüt, oluşturucunun iş parçacığı modelini değiştirmek için yapılan ilk adımdır. Birleştirici kaydetme (veya yalnızca taahhüt), ana iş parçacığı ile birleştirici iş parçacığı arasında bir senkronizasyon adımıdır. Kaydetme işlemi 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 aşağı akış birleştirme kodu tarafından kullanılır. Bu senkronizasyon gerçekleşirken, kopyalama kodu birleştirici iş parçacığında çalışırken ana iş parçacığı yürütmesi durdurulur. Bu işlem, birleştirici iş parçacığı tarafından kopyalanırken ana iş parçacığının oluşturma verilerini değiştirmemesini sağlamak için yapılır.
Engelleme Yapmayan Taahhüt, ana iş parçacığının durması ve kaydetme aşamasının sona ermesini bekleme ihtiyacını ortadan kaldırır. Kayıt, birleştirici iş parçacığında eşzamanlı olarak çalışırken ana iş parçacığı çalışmaya devam eder. Engellemeyen Taahhüt'ün net etkisi, ana iş parçacığında iş oluşturmaya ayrılan süre kısalmasıdır. Bu da ana iş parçacığındaki tıkanıklığı azaltır ve performansı artırır. Bu yazının başlangıcından itibaren (Mart 2022) Engelleme Dışında Taahhüt'ün çalışan bir prototipi var ve bunun performans üzerindeki etkisini ayrıntılı bir şekilde analiz etmeye hazırlanıyoruz.
Ana iş parçacığı dışı birleştirme işlemi, ana iş parçacığından katmanlaştırma işlemini bir çalışan iş parçacığına taşıyarak oluşturma motorunun resimle eşleşmesini sağlamayı amaçlar. Engelleme Olmayan Taahhüt gibi bu da ana iş parçacığındaki tıkanıklığı azaltarak ana iş parçacığının oluşturma iş yükünü hafifletir. Kompozit After Paint'in mimari iyileştirmeleri olmasaydı böyle bir proje mümkün olmazdı.
Ayrıca düzende daha fazla proje mevcut. Nihayet, oluşturma çalışmalarını yeniden dağıtmayla denemeler yapmayı mümkün kılan bir temele sahibiz ve neler yapılabileceğini görmek için çok heyecanlıyız!