Komut dosyaları yüklenirken, tarayıcının bunları yürütmeden önce değerlendirmesi zaman alır. Bu da görevlerin uzun sürmesine 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 çoğu tavsiye, etkileşimleri optimize etmektir. Örneğin, uzun görevleri optimize etme kılavuzunda setTimeout
ile verim sağlama gibi teknikler ele alınmaktadır. Bu teknikler, uzun görevlerden kaçınarak ana iş parçacığına biraz nefes alma alanı tanıdığı için yararlıdır. Bu sayede, tek bir uzun görev için beklemek yerine daha fazla etkileşim ve diğer etkinliğin daha erken çalışması için daha fazla fırsat elde edilebilir.
Ancak komut dosyalarının yüklenmesinden kaynaklanan uzun görevler ne olacak? Bu görevler kullanıcı etkileşimlerini engelleyebilir ve sayfanın yükleme sırasındaki INP'sini etkileyebilir. Bu kılavuzda, tarayıcıların komut dosyası değerlendirmesi tarafından başlatılan görevleri nasıl işlediği incelenecek ve sayfa yüklenirken ana iş parçacığınızın kullanıcı girişine daha duyarlı olabilmesi için komut dosyası değerlendirme çalışmasını bölmek üzere neler yapabileceğiniz ele alınacaktır.
Komut dosyası değerlendirmesi nedir?
Çok fazla JavaScript yayınlayan bir uygulamanın profilini oluşturduysanız sorunun kaynağının Komutu Değerlendir olarak etiketlendiği uzun görevler görmüş olabilirsiniz.
JavaScript yürütmeden hemen önce derlendiğinden komut dosyası değerlendirmesi, JavaScript'in tarayıcıda yürütülmesinin gerekli bir parçasıdır. Bir komut dosyası değerlendirilirken önce hata olup olmadığına bakılır. Ayrıştırıcı hata bulamazsa komut dosyası bytecode olarak derlenir ve ardından yürütülmeye devam edebilir.
Gerekli olsa da kullanıcılar bir sayfa ilk oluşturulduktan kısa bir süre sonra sayfayla etkileşim kurmaya çalışabileceğinden komut dosyası değerlendirmesi sorunlu olabilir. Ancak bir sayfanın oluşturulmuş olması, sayfanın yüklenmesi işleminin tamamlandığı anlamına gelmez. Sayfa komut dosyalarını değerlendirirken meşgul olduğu için yükleme sırasında gerçekleşen etkileşimler gecikebilir. Bu aşamada bir etkileşimin gerçekleşebileceğinin garantisi yoktur (sorumlu komut dosyası henüz yüklenmemiş olabilir). Bununla birlikte, JavaScript'e bağlı olan ve hazır olan etkileşimler olabilir veya etkileşim hiç 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 tipik bir <script>
öğesiyle mi yoksa type=module
ile yüklenen bir modülle mi yüklenmesine bağlıdır. Tarayıcılar her şeyi farklı şekilde ele alma eğiliminde olduğundan, büyük tarayıcı motorlarının komut dosyası değerlendirmesini nasıl ele aldığına değinilecek ve komut dosyası değerlendirme davranışları arasında farklılıklar olduğunda bunlara değinilecektir.
<script>
öğesiyle yüklenen komut dosyaları
Komut dosyalarını değerlendirmek için gönderilen görev 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ğerlendirilmesini sağlayan bir görev 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 bu paketleyiciyi, sayfanızın çalışması için ihtiyaç duyduğu her şeyi tek bir komut dosyasında paketleyecek şekilde yapılandırdığınızı varsayalım. Web siteniz için durum böyleyse söz konusu komut dosyasını değerlendirmek üzere tek bir görev gönderilir. Bu kötü bir durum mu? Bu komut dosyası çok büyük olmadığı sürece bu durum söz konusu değildir.
Büyük JavaScript parçaları yüklemekten kaçınarak komut dosyası değerlendirme çalışmasını bölebilir ve ek <script>
öğeleri kullanarak daha fazla sayıda ayrı, küçük komut dosyası yükleyebilirsiniz.
Sayfa yükleme sırasında her zaman mümkün olduğunca az JavaScript yüklemeye çalışmalısınız. Ancak 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ç engellemeyecek veya en azından başladığınızdan daha az sayıda küçük görev elde etmenizi sağlar.
Komut dosyası değerlendirmesi için görevlerin bölünmesini, etkileşim sırasında çalışan etkinlik geri çağırmalarında veriye geçmeye biraz benzetebilirsiniz. Ancak komut dosyası değerlendirmesinde, asıl iş parçasını engelleme olasılığı daha yüksek olan daha az sayıda büyük komut dosyası yerine, yüklediğiniz JavaScript'i birden çok küçük komut dosyasına bölen verme mekanizması kullanılır.
<script>
öğesi ve type=module
özelliğiyle yüklenen komut dosyaları
Artık <script>
öğesindeki type=module
özelliği ile ES modüllerini tarayıcıya yerel olarak yükleyebilirsiniz. Komut dosyası yüklemeyle ilgili bu yaklaşım, özellikle harita içe aktarma ile birlikte kullanıldığında, kodları ü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 değişen görevler planlar.
Chromium tabanlı tarayıcılar
Chrome gibi tarayıcılarda veya bu tarayıcılardan türetilen tarayıcılarda type=module
özelliğini kullanarak ES modüllerini yüklemek, normalde type=module
kullanmadığınızda gördüğünüzden farklı türde görevler oluşturur. Örneğin, her modül komut dosyası için Modülü derle olarak etiketlenmiş etkinliği içeren bir görev çalıştırılır.
Modüller derlendikten sonra, bu modüllerde daha sonra çalıştırılan tüm kodlar Modülü değerlendir olarak etiketlenen etkinliği başlatır.
Bu durumda, en azından Chrome ve ilgili tarayıcılarda, ES modülleri kullanıldığında derleme adımlarının bölünmesi söz konusudur. Bu, uzun görevleri yönetme açısından net bir kazançtır. Ancak, bunun sonucunda ortaya çıkan modül değerlendirme çalışması, kaçınılmaz bazı maliyetlere katlanmanız anlamına gelir. Mümkün olduğunca az JavaScript göndermeye çalışmalısınız. Ancak tarayıcıdan bağımsız olarak ES modüllerini kullanmak aşağıdaki avantajları sağlar:
- Tüm modül kodları otomatik olarak katı modda çalıştırılır. Bu, JavaScript motorlarının katı olmayan bir bağlamda yapılamayan olası optimizasyonlar yapmasına olanak tanır.
type=module
kullanılarak yüklenen komut dosyaları varsayılan olarak ertelenmiş olarak değerlendirilir. Bu davranışı değiştirmek içintype=module
ile yüklenen komut dosyalarındaasync
özelliğini kullanabilirsiniz.
Safari ve Firefox
Modüller Safari ve Firefox'a yüklendiğinde her biri ayrı bir görevde değerlendirilir. Bu, diğer modüllere yalnızca statik import
ifadelerinden oluşan tek bir üst düzey modül yükleyebileceğiniz anlamına gelir. Yüklenen her modül, değerlendirilmesi için ayrı bir ağ isteği ve görevi oluşturur.
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 olması gereken statik import
ifadelerin aksine dinamik import()
çağrısı, bir JavaScript parçasını isteğe bağlı olarak 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 avantaja sahiptir:
- Yüklenmesi 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ığı, kullanıcı etkileşimlerine daha duyarlı olabilir.
- Dinamik
import()
çağrıları yapıldığında her çağrı, her modülün derlenmesini ve değerlendirilmesini kendi görevine etkili bir şekilde 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örevi başlatır. Bu da etkileşim dinamikimport()
çağrısıyla aynı anda gerçekleşirse ana iş parçacığının kullanıcı girişine yanıt verme özelliğini etkileyebilir. Bu nedenle, mümkün olduğunca az JavaScript yüklemeniz ç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ıyla aynı olur.
Web çalışanına 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 işçisini kaydeden kodun ana iş parçacığında çalışmasına rağmen web işçisindeki kodun çalışmaması açısından son derece faydalıdır. Bu sayede ana ileti dizisindeki tıkanıklığı azaltabilir ve ana ileti dizisinin kullanıcı etkileşimlerine daha duyarlı olmasını sağlayabilirsiniz.
Web çalışanları, ana iş parçacığı çalışmasını azaltmanın yanı sıra modül çalışanlarını destekleyen tarayıcılarda importScripts
veya statik import
ifadeleri aracılığıyla çalışan bağlamında kullanılacak harici komut dosyaları da kendileri yükleyebilir. Sonuç olarak, bir web çalışanı tarafından istenen tüm komut dosyaları ana iş parçacığının dışında değerlendirilir.
Karşılaştırmalar ve dikkat edilmesi gereken noktalar
Komut dosyalarınızı ayrı ve daha küçük dosyalara bölmek, daha az sayıda çok daha büyük dosya yüklemek yerine uzun görevleri sınırlandırmaya yardımcı olsa da komut dosyalarını nasıl böleceğinize karar verirken bazı noktaları göz önünde bulundurmanız önemlidir.
Sıkıştırma verimliliği
Komut dosyalarını bölme konusunda sıkıştırma da bir faktördür. Komut dosyaları ne kadar küçük olursa sıkıştırma o kadar az etkili olur. 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şimi sağlamak için yeterince küçük parçalara ayırmanız gerekir.
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
SplitChunksPlugin
eklentisi yardımcı olabilir. Öğe boyutlarını yönetmeye yardımcı olması için ayarlayabileceğiniz seçenekler içinSplitChunksPlugin
belgelerine bakın. - Rollup ve esbuild gibi diğer paketleyiciler için kodunuzda dinamik
import()
çağrıları kullanarak komut dosyası dosya boyutlarını yönetebilirsiniz. Webpack'in yanı sıra bu paketleyiciler, dinamik olarak içe aktarılan öğeyi otomatik olarak kendi dosyasına ayırır. Böylece, başlangıçtaki paket boyutları daha büyük olmaz.
Önbelleği geçersiz kılma
Önbelleğin geçersiz kılınması, bir sayfanın tekrar ziyaretlerde ne kadar hızlı yüklenmesinde büyük rol oynar. Büyük, tek parça komut dosyası paketleri yayınladığınızda 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 yeniden indirilmesi gerekmesidir.
Komut dosyalarınızı bölerek yalnızca komut dosyası değerlendirme çalışmasını daha küçük görevlere bölemezsiniz, aynı zamanda geri gelen ziyaretçilerin ağ yerine tarayıcı önbelleğinden daha fazla komut dosyası alma olasılığını da artırırsınız. Bu da sayfanın genel olarak daha hızlı yüklenmesine yol açar.
İç içe yerleştirilmiş modüller ve yükleme performansı
ES modüllerini üretimde gönderiyor ve type=module
özelliğiyle yüklüyorsanız modül iç içe yerleştirmenin başlatma süresini nasıl etkileyebileceğini bilmeniz 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ıdır:
// a.js
import {b} from './b.js';
// b.js
import {c} from './c.js';
ES modülleriniz birlikte gruplandırılmamışsa önceki kod bir ağ isteği zincirine neden olur: <script>
öğesinden a.js
istendiğinde b.js
için başka bir ağ isteği gönderilir. Bu istek daha sonra c.js
için başka bir istek içerir. Bunu önlemenin bir yolu, bir paketleyici kullanmaktır. Ancak paketleyicinizi, komut dosyası değerlendirme çalışmalarını dağıtmak için komut dosyalarını bölecek şekilde yapılandırdığınızdan emin olun.
Paketleyici kullanmak istemiyorsanız iç içe yerleştirilmiş modül çağrılarını atlatmanın bir başka yolu da modulepreload
kaynak ipucunu kullanmaktır. Bu ipucu, ağ istek zincirlerini önlemek için ES modüllerini önceden yükler.
Sonuç
Tarayıcıda komut dosyalarının değerlendirmesini optimize etmek hiç şüphesiz zor bir iş. 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öreve dağıtırsınız. Böylece ana iş parçacığının engellenmesini önler ve ana iş parçacığına kullanıcı etkileşimlerini daha verimli bir şekilde yönetme olanağı tanırsınız.
Özetlemek gerekirse, büyük komut dosyası değerlendirme görevlerini bölmek için yapabileceğiniz bazı işlemler şunlardır:
type=module
özelliği olmadan<script>
öğesini kullanarak komut dosyaları yüklerken çok büyük komut dosyaları yüklemekten kaçının. Aksi takdirde, ana iş parçacığını engelleyen, kaynak kullanımı yoğun komut dosyası değerlendirme görevleri başlatılır. Bu işi bölmek için komut dosyalarınızı daha fazla<script>
öğesine dağıtın.- ES modüllerini tarayıcıya yerel olarak yüklemek için
type=module
özelliğini kullandığınızda her bir modül komut dosyası için ayrı değerlendirme görevleri başlatılır. - Dinamik
import()
çağrıları kullanarak ilk paketlerinizin boyutunu küçültün. Bu, paketleyicilerde de işe yarar. Paketleyiciler, dinamik olarak içe aktarılan her modülü "bölme 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ğin geçersiz kılınması gibi değişkenleri göz önünde bulundurun. Daha büyük komut dosyaları daha iyi sıkıştırılır ancak daha az sayıda görevde daha pahalı komut dosyası değerlendirme çalışması içerme olasılıkları daha yüksektir ve tarayıcı önbelleğini geçersiz kılar. Bu da genel olarak daha düşük önbelleğe alma verimliliğine yol açar.
- ES modüllerini paketlenmemiş olarak kullanıyorsanız başlangıç sırasında yüklemelerini optimize etmek için
modulepreload
kaynak ipucunu kullanın. - Her zaman olduğu gibi, mümkün olduğunca az JavaScript gönderin.
Bu kesinlikle bir dengeleme işidir. Ancak komut dosyalarını bölerek ve dinamik import()
ile ilk yükleyicileri azaltarak daha iyi bir başlatma performansı elde edebilir ve bu önemli başlatma 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ı olacaktır.