Komut dosyaları yüklenirken tarayıcının bunları yürütmeden önce değerlendirmesi zaman alır ve bu durum uzun görevlere neden olabilir. Komut dosyası değerlendirmesinin nasıl çalıştığını ve sayfa yükleme sırasında uzun görevlere neden olmasını önlemek için neler yapabileceğinizi öğrenin.
Interaction to Next Paint (INP) metriğini optimize etme konusunda karşılaşacağınız tavsiyelerin çoğu, etkileşimlerin kendisini optimize etmeye yöneliktir. Örneğin, uzun görevleri optimize etme kılavuzunda setTimeout ile sonuç verme gibi teknikler ele alınır. Bu teknikler, uzun süren görevlerden kaçınarak ana iş parçacığına biraz zaman tanır. Bu sayede, etkileşimler ve diğer etkinlikler tek bir uzun süren görevin tamamlanmasını beklemek yerine daha erken çalıştırılabilir.
Ancak, komut dosyalarını yüklemekten kaynaklanan uzun görevler ne olacak? Bu görevler, kullanıcı etkileşimlerini engelleyebilir ve yükleme sırasında sayfanın INP'sini etkileyebilir. Bu rehberde, tarayıcıların komut dosyası değerlendirmesiyle başlatılan görevleri nasıl işlediği ve sayfa yüklenirken ana iş parçacığınızın kullanıcı girişine daha duyarlı olması için komut dosyası değerlendirme işini nasıl bölebileceğiniz ele alınacaktır.
Komut dosyası değerlendirmesi nedir?
Çok fazla JavaScript içeren bir uygulamanın profilini oluşturduysanız Evaluate Script olarak etiketlenen uzun görevler görmüş olabilirsiniz.
JavaScript, yürütülmeden hemen önce derlendiğinden komut dosyası değerlendirmesi, tarayıcıda JavaScript'in yürütülmesi için gereklidir. Bir komut dosyası değerlendirilirken önce hatalar için ayrıştırılır. Ayrıştırıcı hata bulmazsa komut dosyası bayt koduna derlenir ve yürütülmeye devam edebilir.
Gerekli olsa da kullanıcılar, ilk oluşturulmasından kısa bir süre sonra bir sayfayla etkileşim kurmaya çalışabileceğinden komut dosyası değerlendirmesi sorunlu olabilir. Ancak bir sayfanın oluşturulmuş olması, yüklenmesinin tamamlandığı anlamına gelmez. Sayfa, komut dosyalarını değerlendirmekle meşgul olduğundan yükleme sırasında gerçekleşen etkileşimler gecikebilir. Bu noktada bir etkileşimin gerçekleşebileceği garanti edilmese de (bununla ilgili komut dosyası henüz yüklenmemiş olabilir) JavaScript'e bağlı ve hazır etkileşimler olabilir veya etkileşim tamamen JavaScript'e bağlı olmayabilir.
Komut dosyaları ile bunları değerlendiren görevler arasındaki ilişki
Komut dosyası değerlendirmesinden sorumlu görevlerin nasıl başlatılacağı, yüklediğiniz komut dosyasının normal bir <script> öğesiyle mi yoksa type=module ile yüklenen bir modül mü olduğuna bağlıdır. Tarayıcılar, işlemleri farklı şekilde ele alma eğiliminde olduğundan, büyük tarayıcı motorlarının komut dosyası değerlendirmesini nasıl ele aldığı, komut dosyası değerlendirme davranışlarının farklılık gösterdiği yerlerde ele alınacaktır.
<script> öğesiyle yüklenen komut dosyaları
Komut dosyalarını değerlendirmek için gönderilen görevlerin sayısı genellikle bir sayfadaki <script> öğelerinin sayısıyla doğrudan ilişkilidir. Her <script> öğesi, istenen komut dosyasının ayrıştırılması, derlenmesi ve yürütülmesi için değerlendirileceği bir görevi başlatır. Bu durum Chromium tabanlı tarayıcılar, Safari ve Firefox için geçerlidir.
Bu neden önemli? Üretim komut dosyalarınızı yönetmek için bir paketleyici kullandığınızı ve sayfanızın çalışması için gereken her şeyi tek bir komut dosyasında paketleyecek şekilde yapılandırdığınızı varsayalım. Web sitenizde bu durum geçerliyse söz konusu komut dosyasını değerlendirmek için tek bir görev gönderileceğini düşünebilirsiniz. Bu olumsuz bir durum mu? Bu, büyük bir komut dosyası olmadığı sürece gerekli değildir.
Büyük JavaScript parçalarını yüklemekten kaçınarak komut dosyası değerlendirme işini bölebilir ve ek <script> öğelerini kullanarak daha fazla sayıda ayrı ve küçük komut dosyası yükleyebilirsiniz.
Sayfa yükleme sırasında her zaman mümkün olduğunca az JavaScript yüklemeye çalışmanız gerekse de komut dosyalarınızı bölmek, ana iş parçacığını engelleyebilecek tek bir büyük görev yerine, ana iş parçacığını hiç engellemeyen veya en azından başlangıçta olduğundan daha az engelleyen daha fazla sayıda küçük görev olmasını sağlar.
<script> öğesi bulunduğundan komut dosyalarını değerlendirmek için birden fazla görev oluşturuldu. Bu, ana iş parçacığını engelleme olasılığı daha yüksek olan tek bir büyük komut dosyası paketi göndermek yerine tercih edilir.
Senaryo değerlendirmesi için görevleri bölmeyi, etkileşim sırasında çalışan etkinlik geri çağırmaları sırasında kontrolü bırakmaya benzetebilirsiniz. Ancak komut dosyası değerlendirmesinde, kontrolü başka bir işleme bırakma mekanizması, yüklediğiniz JavaScript'i ana iş parçacığını engelleme olasılığı daha yüksek olan daha az sayıda büyük komut dosyası yerine birden fazla küçük komut dosyasına böler.
<script> öğesi ve type=module özelliğiyle yüklenen komut dosyaları
Artık <script> öğesinde type=module özelliği ile ES modüllerini tarayıcıya yerel olarak yüklemek mümkün. Bu komut dosyası yükleme yaklaşımı, özellikle import maps ile birlikte kullanıldığında, kodu üretim kullanımı için dönüştürmek zorunda kalmamak gibi bazı geliştirici deneyimi avantajları sunar. Ancak komut dosyalarını bu şekilde yüklemek, tarayıcıdan tarayıcıya farklılık gösteren görevleri planlar.
Chromium tabanlı tarayıcılar
Chrome gibi tarayıcılarda veya Chrome'dan türetilen tarayıcılarda, type=module özelliği kullanılarak ES modüllerinin yüklenmesi, normalde type=module özelliği kullanılmadığında gördüğünüzden farklı türde görevler üretir. Örneğin, her modül komut dosyası için Modülü derle olarak etiketlenen etkinliği içeren bir görev çalıştırılır.
Modüller derlendikten sonra, bunlarda çalıştırılan tüm kodlar Modülü değerlendir olarak etiketlenen etkinliği başlatır.
Buradaki etki (en azından Chrome ve ilgili tarayıcılarda), ES modülleri kullanılırken derleme adımlarının bölünmesidir. Bu, uzun görevleri yönetme açısından açık bir kazançtır. Ancak ortaya çıkan modül değerlendirme çalışması, kaçınılmaz bir maliyete katlanmanız anlamına gelir. Mümkün olduğunca az JavaScript göndermeye çalışmanız gerekse de tarayıcıdan bağımsız olarak ES modüllerini kullanmak aşağıdaki avantajları sağlar:
- Tüm modül kodu, yüksek düzey modunda otomatik olarak çalıştırılır. Bu mod, JavaScript motorlarının katı olmayan bir bağlamda yapılamayacak olası optimizasyonları yapmasına olanak tanır.
type=modulekullanılarak yüklenen komut dosyaları, varsayılan olarak ertelenmiş gibi değerlendirilir. Bu davranışı değiştirmek içinasyncözelliği,type=moduleile yüklenen komut dosyalarında kullanılabilir.
Safari ve Firefox
Modüller Safari ve Firefox'ta yüklendiğinde her biri ayrı bir görevde değerlendirilir. Bu, teorik olarak yalnızca statik import ifadelerden oluşan tek bir üst düzey modülü diğer modüllere yükleyebileceğiniz ve yüklenen her modülün değerlendirilmesi için ayrı bir ağ isteği ve görev oluşturulacağı anlamına gelir.
Dinamik import() ile yüklenen komut dosyaları
Dinamik import(), komut dosyalarını yüklemenin başka bir yöntemidir. Bir ES modülünün en üstünde bulunması gereken statik import ifadelerinin aksine, dinamik import() çağrısı, JavaScript parçası yüklemek için komut dosyasının herhangi bir yerinde görünebilir. Bu tekniğe kod bölme denir.
Dinamik import(), INP'yi iyileştirme konusunda iki avantaj sunar:
- Daha sonra yüklenmek üzere ertelenen modüller, o sırada yüklenen JavaScript miktarını azaltarak başlangıç sırasında ana iş parçacığı çekişmesini azaltır. Bu sayede ana iş parçacığı serbest kalır ve kullanıcı etkileşimlerine daha hızlı yanıt verebilir.
- Dinamik
import()çağrıları yapıldığında her çağrı, her modülün derlenmesini ve değerlendirilmesini kendi görevine ayırır. Elbette, çok büyük bir modülü yükleyen dinamik birimport(), oldukça büyük bir komut dosyası değerlendirme görevini başlatır. Etkileşim, dinamikimport()çağrısıyla aynı anda gerçekleşirse bu durum, ana iş parçacığının kullanıcı girişine yanıt verme yeteneğini etkileyebilir. Bu nedenle, mümkün olduğunca az JavaScript yüklemeniz hâlâ çok önemlidir.
Dinamik import() çağrıları, tüm büyük tarayıcı motorlarında benzer şekilde çalışır: Sonuç olarak ortaya çıkan komut dosyası değerlendirme görevleri, dinamik olarak içe aktarılan modül sayısı kadar olur.
Web çalışanı içinde yüklenen komut dosyaları
Web çalışanları, özel bir JavaScript kullanım alanıdır. Web çalışanları ana iş parçacığına kaydedilir ve çalışandaki kod kendi iş parçacığında çalışır. Bu, web çalışanı kaydeden kod ana iş parçacığında çalışırken web çalışanı içindeki kodun çalışmaması açısından büyük avantaj sağlar. Bu sayede ana iş parçacığındaki tıkanıklık azalır ve ana iş parçacığının kullanıcı etkileşimlerine daha duyarlı olması sağlanabilir.
Web çalışanları, ana iş parçacığı işini azaltmanın yanı sıra kendileri de çalışan bağlamında kullanılacak harici komut dosyalarını yükleyebilir. Bu işlem, modül çalışanlarını destekleyen tarayıcılarda importScripts veya statik import ifadeleri aracılığıyla yapılabilir. Sonuç olarak, bir web çalışanı tarafından istenen tüm komut dosyaları ana iş parçacığı dışında değerlendirilir.
Artıları ve eksileri değerlendirme
Komut dosyalarınızı ayrı ve daha küçük dosyalara bölmek, daha az sayıda ancak çok daha büyük dosyalar yüklemeye kıyasla uzun görevleri sınırlamaya yardımcı olsa da komut dosyalarını nasıl böleceğinize karar verirken bazı şeyleri göz önünde bulundurmanız önemlidir.
Sıkıştırma verimliliği
Senaryoları bölme konusunda sıkıştırma önemli bir faktördür. Komut dosyaları küçüldüğünde sıkıştırma biraz daha az verimli hale gelir. Daha büyük komut dosyaları, sıkıştırmadan çok daha fazla yararlanır. Sıkıştırma verimliliğini artırmak, komut dosyalarının yükleme sürelerini mümkün olduğunca düşük tutmaya yardımcı olsa da komut dosyalarını, başlatma sırasında daha iyi etkileşim sağlamak için yeterince küçük parçalara ayırdığınızdan emin olmak biraz denge gerektirir.
Paketleyiciler, web sitenizin bağlı olduğu komut dosyalarının çıkış boyutunu yönetmek için ideal araçlardır:
- Webpack söz konusu olduğunda
SplitChunksPlugineklentisi yardımcı olabilir. Öğe boyutlarını yönetmeye yardımcı olacak seçenekler içinSplitChunksPlugindokümanlarına bakın. - Rollup ve esbuild gibi diğer paketleyiciler için kodunuzda dinamik
import()çağrıları kullanarak komut dosyası boyutu yönetebilirsiniz. Bu paketleyiciler ve webpack, dinamik olarak içe aktarılan öğeyi otomatik olarak kendi dosyasına ayırarak daha büyük başlangıç paketi boyutlarını önler.
Önbelleği geçersiz kılma
Önbellek geçersiz kılma, bir sayfanın tekrar ziyaretlerde ne kadar hızlı yüklendiğinde büyük rol oynar. Büyük ve tek bir dosyadan oluşan komut dosyası paketleri gönderdiğinizde tarayıcı önbelleğe alma konusunda dezavantajlı olursunuz. Bunun nedeni, birinci taraf kodunuzu güncellediğinizde (paketleri güncelleyerek veya hata düzeltmelerini göndererek) paketin tamamının geçersiz hale gelmesi ve tekrar indirilmesi gerekmesidir.
Komut dosyalarınızı bölerek yalnızca komut dosyası değerlendirme işini daha küçük görevlere bölmekle kalmaz, aynı zamanda geri gelen ziyaretçilerin ağ yerine tarayıcı önbelleğinden daha fazla komut dosyası alması olasılığını da artırırsınız. Bu da genel olarak daha hızlı sayfa yükleme anlamına gelir.
İç içe yerleştirilmiş modüller ve yükleme performansı
Üretimde ES modülleri gönderiyorsanız ve bunları type=module özelliğiyle yüklüyorsanız modül yerleştirmenin başlangıç süresini nasıl etkileyebileceğinin farkında olmanız gerekir. Modül iç içe yerleştirme, bir ES modülünün statik olarak başka bir ES modülünü içe aktarması ve bu modülün de statik olarak başka bir ES modülünü içe aktarması anlamına gelir:
// a.js
import {b} from './b.js';
// b.js
import {c} from './c.js';
ES modülleriniz birlikte paketlenmemişse yukarıdaki kod bir ağ isteği zinciriyle sonuçlanır: a.js, <script> öğesinden istendiğinde b.js için başka bir ağ isteği gönderilir. Bu istek de c.js için başka bir isteği içerir. Bunu önlemenin bir yolu, paketleyici kullanmaktır. Ancak paketleyicinizi, komut dosyası değerlendirme işini yaymak için komut dosyalarını ayıracak şekilde yapılandırdığınızdan emin olun.
Paketleyici kullanmak istemiyorsanız iç içe yerleştirilmiş modül çağrılarını aşmanın bir başka yolu da modulepreload kaynak ipucunu kullanmaktır. Bu ipucu, ağ isteği zincirlerini önlemek için ES modüllerini önceden yükler.
Sonuç
Tarayıcıdaki komut dosyalarının değerlendirmesini optimize etmek zorlu bir iştir. Yaklaşım, web sitenizin gereksinimlerine ve kısıtlamalarına bağlıdır. Ancak komut dosyalarını bölerek komut dosyası değerlendirme işini çok sayıda küçük görev arasında yayarsınız. Bu nedenle, ana ileti dizisini engellemek yerine ana ileti dizisine kullanıcı etkileşimlerini daha verimli bir şekilde işleme olanağı tanırsınız.
Özetlemek gerekirse büyük senaryo değerlendirme görevlerini bölmek için yapabileceklerinizden bazıları şunlardır:
type=moduleözelliği olmadan<script>öğesini kullanarak komut dosyalarını yüklerken çok büyük olan komut dosyalarını yüklemekten kaçının. Bu komut dosyaları, ana iş parçacığını engelleyen kaynak yoğun komut dosyası değerlendirme görevlerini başlatır. Bu çalışmayı bölmek için senaryolarınızı daha fazla<script>öğesine yayın.- ES modüllerini tarayıcıda yerel olarak yüklemek için
type=moduleözelliğini kullanmak, her ayrı modül komut dosyası için değerlendirme amacıyla ayrı görevler başlatır. - Dinamik
import()çağrıları kullanarak ilk paketlerinizin boyutunu küçültün. Bu, paketleyicilerde de çalışır. Paketleyiciler, dinamik olarak içe aktarılan her modülü "bölünme noktası" olarak değerlendirir. Bu da dinamik olarak içe aktarılan her modül için ayrı bir komut dosyası oluşturulmasına neden olur. - Sıkıştırma verimliliği ve önbelleği geçersiz kılma gibi ödünleri değerlendirdiğinizden emin olun. Daha büyük komut dosyaları daha iyi sıkıştırılır ancak daha az görevde daha maliyetli komut dosyası değerlendirme çalışması içerme ve tarayıcı önbelleğinin geçersiz kılınmasına neden olma olasılığı daha yüksektir. Bu da genel olarak daha düşük önbelleğe alma verimliliğine yol açar.
- ES modüllerini paketlemeden yerel olarak kullanıyorsanız başlatma sırasında yüklenmelerini optimize etmek için
modulepreloadkaynak ipucunu kullanın. - Her zaman olduğu gibi, mümkün olduğunca az JavaScript gönderin.
Bu kesinlikle bir denge işidir. Ancak komut dosyalarını bölerek ve dinamik import() ile ilk yükleri azaltarak daha iyi başlangıç performansı elde edebilir ve bu kritik başlangıç döneminde kullanıcı etkileşimlerini daha iyi karşılayabilirsiniz. Bu, INP metriğinde daha iyi puan almanıza ve dolayısıyla daha iyi bir kullanıcı deneyimi sunmanıza yardımcı olur.