Komut dosyalarını yüklerken, tarayıcının komut dosyalarını yürütmeden önce değerlendirmesi zaman alır ve bu da uzun görevlere neden olabilir. Komut dosyası değerlendirmesinin işleyiş şeklini ve sayfa yükleme sırasında uzun görevlere neden olmaması için neler yapabileceğinizi öğrenin.
Sonraki Boyama Etkileşimi (INP) optimizasyonu söz konusu olduğunda karşılaşacağınız önerilerin çoğu, etkileşimlerin kendilerinin optimize edilmesidir. Örneğin, uzun görevleri optimize etme kılavuzunda, setTimeout
ve diğerleriyle getiri elde etme gibi teknikler ele alınmaktadır. Bu teknikler, uzun görevlerden kaçınarak ana iş parçacığına biraz boşluk bırakması açısından yararlıdır. Böylece, tek bir uzun görevi beklemek yerine etkileşimlerin ve diğer aktivitelerin daha erken gerçekleştirilmesi için daha fazla fırsat yaratılabilir.
Peki, komut dosyalarının kendisinin yüklenmesinden gelen uzun görevler ne olacak? Bu görevler, kullanıcı etkileşimlerini etkileyebilir ve yükleme sırasında bir sayfanın INP'sini etkileyebilir. Bu kılavuzda tarayıcıların komut dosyası değerlendirmesiyle başlatılan görevleri nasıl gerçekleştirdiği keşfedilecek ve ana iş parçacığınızın sayfa yüklenirken kullanıcı girişine daha duyarlı olabilmesi için komut dosyası değerlendirme çalışmasını nasıl ayırabileceğinize bakacağız.
Senaryo değerlendirme nedir?
Çok sayıda JavaScript gönderen bir uygulamanın profilini oluşturduysanız suçlunun Değerlendirme Komut Dosyası olarak etiketlendiği uzun görevler görmüş olabilirsiniz.
![Chrome Geliştirici Araçları'nın performans profil aracında görsel olarak sunulan komut dosyası değerlendirme işlemi İş, başlatma sırasında uzun bir göreve neden olur. Bu da ana iş parçacığının kullanıcı etkileşimlerine yanıt vermesini engeller.](https://web.dev/static/articles/script-evaluation-and-long-tasks/image/script-evaluation-as-vis-17dff4e25f1c8.png?authuser=5&hl=tr)
JavaScript yürütmeden önce tam zamanında derlendiğinden, komut dosyası değerlendirmesi, tarayıcıda JavaScript yürütmenin gerekli bir parçasıdır. Bir komut dosyası değerlendirilirken ilk olarak hatalar için ayrıştırılır. Ayrıştırıcı hata bulamazsa komut dosyası bayt kodu olarak derlenir ve ardından yürütmeye devam edebilir.
Kullanıcılar bir sayfa ilk oluşturulduktan kısa bir süre sonra etkileşimde bulunmaya çalışabileceğinden, komut dosyası değerlendirmesi sorunlu olabilir. Ancak bir sayfanın oluşturulmuş olması, sayfanın 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. Etkileşimin, söz konusu noktada (ilgili komut dosyası henüz yüklenmemiş olabileceği için) gerçekleşebileceğine dair bir garanti verilmese de, hazır olan JavaScript'e bağlı etkileşimler olabilir ya da etkileşimin JavaScript'e bağlı olmaması söz konusu olabilir.
Senaryolar ve 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 yüklendiğine yoksa type=module
ile yüklenen bir modül mü olduğuna bağlıdır. Tarayıcılar işleri farklı şekilde ele alma eğilimine sahip olduğundan, başlıca tarayıcı motorlarının komut dosyası değerlendirmesini nasıl ele aldığına, bunlar arasındaki komut dosyası değerlendirme davranışlarının nerede değişiklik gösterdiğine odaklanılacaktır.
<script>
öğesiyle yüklenen komut dosyaları
Komut dosyalarını değerlendirmek için gönderilen görevlerin sayısının, genellikle bir sayfadaki <script>
öğelerinin sayısıyla doğrudan bir ilişkisi vardır. Her <script>
öğesi, istenen komut dosyasının ayrıştırılabilmesi, derlenebilmesi ve yürütülebilmesi için bir görev başlatır. Bu durum Chromium tabanlı tarayıcılar, Safari ve Firefox için de geçerlidir.
Bu neden önemli? Üretim komut dosyalarınızı yönetmek için bir paketleyici kullandığınızı ve bunu, sayfanızın yapması gereken her şeyi tek bir komut dosyası içinde toplayacak şekilde yapılandırdığınızı varsayalım. Web siteniz için bu durum geçerliyse söz konusu komut dosyasını değerlendirmek için tek bir görev gönderilmesini bekleyebilirsiniz. Bu kötü bir şey mi? Komut dosyası çok büyük değilse, şart değil.
Büyük JavaScript parçaları yüklemekten kaçınarak komut dosyası değerlendirme çalışmalarını bölüp ek <script>
öğeleri kullanarak daha küçük boyutlu, bağımsız komut dosyaları 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ı ayırmak, 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örevinizin olmasını sağlar.
![Chrome Geliştirici Araçları'nın performans profil aracında görselleştirildiği şekilde komut dosyası değerlendirmesini içeren birden çok görev. Daha az büyük komut dosyası yerine birden çok küçük komut dosyası yüklendiğinden, görevlerin uzun görevlere dönüşme olasılığı daha düşüktür. Böylece, ana iş parçacığı kullanıcı girişine daha hızlı yanıt verebilir.](https://web.dev/static/articles/script-evaluation-and-long-tasks/image/multiple-tasks-involving-744bb86f09b1a.png?authuser=5&hl=tr)
<script>
öğesi bulunduğundan komut dosyalarını değerlendirmek için birden fazla görev oluşturuldu. Bu, kullanıcılara büyük bir komut dosyası paketi göndermek için tercih edilir; bu durumda büyük olasılıkla ana iş parçacığı engellenir.
Komut dosyası değerlendirmesi için görevleri ayırmayı, etkileşim sırasında çalıştırılan etkinlik geri çağırmaları sırasında verilen getiriye benzetebilirsiniz. Bununla birlikte, komut dosyası değerlendirmesinde getiri mekanizması, ana iş parçacığını engelleme olasılığı daha yüksek olan daha az sayıda büyük komut dosyası yerine, yüklediğiniz JavaScript'i birden fazla küçük komut dosyasına böler.
<script>
öğesi ve type=module
özelliğiyle yüklenen komut dosyaları
Artık ES modüllerini, <script>
öğesinde type=module
özelliğiyle tarayıcıya yerel olarak yükleyebilirsiniz. Komut dosyası yüklemeye yönelik bu yaklaşım, özellikle haritaları içe aktarma ile birlikte kullanıldığında üretimde kullanılmak üzere kodu dönüştürmek zorunda kalmamak gibi bazı geliştirici deneyimi avantajları sunar. Ancak, komut dosyalarının bu şekilde yüklenmesi, tarayıcıdan tarayıcıya farklı görevlerin planlanmasını sağlar.
Chromium tabanlı tarayıcılar
Chrome gibi tarayıcılarda (veya bundan türetilen tarayıcılarda), ES modüllerini type=module
özelliğini kullanarak yüklemek, type=module
kullanılmadığında normalde göreceğinizden farklı türde görevler üretir. Örneğin, her modül komut dosyası için, Modül derle olarak etiketlenmiş bir etkinlik içeren bir görev çalıştırılır.
![Modül derleme, Chrome Geliştirici Araçları'nda görselleştirildiği gibi birden çok görevde çalışır.](https://web.dev/static/articles/script-evaluation-and-long-tasks/image/module-compilation-in-mu-724bec674b5df.png?authuser=5&hl=tr)
Modüller derlendikten sonra, daha sonra bunların içinde çalıştırılan tüm kodlar Değerlendirme modülü olarak etiketlenen etkinliği başlatır.
![Chrome Geliştirici Araçları'nın performans panelinde görselleştirilen bir modülün tam zamanında değerlendirmesi.](https://web.dev/static/articles/script-evaluation-and-long-tasks/image/just-time-evaluation-a-660d5e72fb916.png?authuser=5&hl=tr)
Buradaki etkisi, en azından Chrome'da ve ilgili tarayıcılarda, ES modüllerini kullanırken derleme adımlarının bölünmesidir. Bu, uzun görevleri yönetme açısından açık bir kazanımdır. Ancak sonuçta ortaya çıkan modül değerlendirme çalışması, yine de bazı kaçınılmaz maliyetlere neden olacağınızı gösterir. 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 şu avantajları sağlar:
- Tüm modül kodları otomatik olarak katı modda çalıştırılır. Bu mod, JavaScript motorları tarafından katı olmayan bir bağlamda yapılamayacak olası optimizasyonlara olanak tanır.
type=module
kullanılarak yüklenen komut dosyaları, varsayılan olarak ertelenmiş gibi kabul edilir. Bu davranışı değiştirmek içintype=module
ile yüklenen komut dosyalarındaasync
özelliği kullanılabilir.
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 teorik olarak yalnızca statik import
ifadelerinden oluşan tek bir üst düzey modül yükleyebileceğiniz ve yüklenen her modülün ayrı bir ağ isteği ve değerlendirme görevi gerektireceği anlamına gelir.
Komut dosyaları dinamik import()
ile yüklendi
Dinamik import()
, komut dosyalarını yüklemek için kullanılan başka bir yöntemdir. ES modülünün en üstünde olması gereken statik import
ifadelerinin aksine dinamik import()
çağrısı, istek üzerine JavaScript parçası yüklemek için komut dosyasında herhangi bir yerde görünebilir. Bu tekniğe kod bölme adı verilir.
Dinamik import()
, INP'yi iyileştirme konusunda iki avantaj sunar:
- Daha sonra yüklenmek üzere ertelenen modüller, başlatma sırasında o sırada yüklenen JavaScript miktarını azaltarak ana iş parçacığı anlaşmazlığını azaltır. Böylece ana ileti dizisi serbest bırakılır ve 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ğerlendirmesini kendi görevine etkili bir şekilde ayırır. Elbette çok büyük bir modül yükleyen dinamikimport()
, oldukça büyük bir komut dosyası değerlendirme görevi başlatır ve etkileşim dinamikimport()
çağrısıyla aynı anda gerçekleşirse ana iş parçacığının kullanıcı girişine yanıt vermesini engelleyebilir. Bu nedenle, mümkün olduğunca az JavaScript yüklemeniz yine de çok önemlidir.
Dinamik import()
çağrıları, tüm önemli tarayıcı motorlarında benzer şekilde davranır: Sonuçta ortaya çıkan komut dosyası değerlendirme görevleri, dinamik olarak içe aktarılan modüllerin sayısıyla aynı olur.
Bir 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ışan içindeki kod kendi iş parçacığında çalışır. Bu, web çalışanını kaydeden kod ana iş parçacığında çalışırken, web çalışanı içindeki kodun çalışmaması açısından son derece yararlıdır. Bu, ana ileti dizisi sıkışıklığını azaltır ve ana ileti dizisinin kullanıcı etkileşimlerinde daha duyarlı olmasına yardımcı olabilir.
Ana iş parçacığının işini azaltmanın yanı sıra web çalışanları, çalışan bağlamında kullanılacak harici komut dosyalarını importScripts
veya modül çalışanlarını destekleyen tarayıcılarda statik import
ifadeleri aracılığıyla yükleyebilir. Sonuç olarak, web çalışanı tarafından istenen tüm komut dosyaları ana iş parçacığı dışında değerlendirilir.
Detaylar ve dikkat edilmesi gereken noktalar
Komut dosyalarınızı ayrı, küçük dosyalara bölmek daha az sayıda, çok büyük dosyalar yüklemek yerine uzun görevlerin sınırlanmasına yardımcı olsa da komut dosyalarının nasıl ayrılacağına karar verirken bazı unsurların dikkate alınması önemlidir.
Sıkıştırma verimliliği
Komut dosyalarının bölünmesi söz konusu olduğunda sıkıştırma bir faktördür. Komut dosyaları daha küçük olduğunda, sıkıştırma biraz daha az verimli hale gelir. Büyük komut dosyaları, sıkıştırmadan çok daha fazla faydalanır. Sıkıştırma verimliliğini artırmak komut dosyalarının yükleme sürelerini mümkün olduğunca kısa tutmaya yardımcı olur. Ancak bu işlem, başlatma sırasında daha iyi etkileşim kurmayı kolaylaştırmak amacıyla komut dosyalarını yeterli sayıda küçük parçalara böldüğünüzden emin olmak için dengeyi korumanızı sağlar.
Paketleyiciler, web sitenizin bağlı olduğu komut dosyalarının çıktı boyutunu yönetmek için ideal araçlardır:
- Webpack'in önemli olduğu durumlarda
SplitChunksPlugin
eklentisinden yararlanabilirsiniz. Öğe boyutlarını yönetmeye yardımcı olacak seçenekleri belirlemek içinSplitChunksPlugin
belgelerini inceleyin. - Rollup ve esbuild gibi diğer paketleyiciler için kodunuzda dinamik
import()
çağrılarını kullanarak komut dosyası boyutlarını yönetebilirsiniz. Web paketinin yanı sıra bu paketleyiciler, dinamik olarak içe aktarılan öğeyi otomatik olarak kendi dosyasına ayırır. Böylece ilk paket boyutlarının daha büyük olmasını önlersiniz.
Önbelleği geçersiz kılma
Önbelleği geçersiz kılma, yinelenen ziyaretlerde bir sayfanın ne kadar hızlı yüklendiğini belirlemede büyük bir rol oynar. Büyük, monolitik komut dosyası paketleri gönderdiğinizde, tarayıcı önbelleğine alma konusunda dezavantajlı olursunuz. Bunun nedeni, paketleri güncelleme veya gönderimle ilgili hata düzeltmeleri aracılığıyla birinci taraf kodunuzu güncellediğinizde tüm paketin geçersiz hale gelmesi ve tekrar indirilmesi gerekmesidir.
Komut dosyalarınızı parçalara ayırarak sadece küçük görevlerde komut dosyası değerlendirme çalışmasını yarıda bırakmakla kalmaz, 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 sayfaların genel olarak daha hızlı yüklenmesini sağlar.
İç 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ştirmesi, bir ES modülünün başka bir ES modülünü statik olarak içe aktaran başka bir ES modülünü statik olarak içe aktarmasını ifade eder:
// a.js
import {b} from './b.js';
// b.js
import {c} from './c.js';
ES modülleriniz birlikte paketlenmemişse önceki kod bir ağ isteği zinciri oluşturur: Bir <script>
öğesinden a.js
istendiğinde b.js
için başka bir ağ isteği gönderilir ve bu istek de c.js
için başka bir istek içerir. Bunu önlemenin bir yolu paketleyici kullanmaktır. Ancak, paketleyicinizi komut dosyası değerlendirme çalışmalarını 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, ağ isteği zincirlerinden kaçınmak için ES modüllerini önceden yükleyecektir.
Sonuç
Tarayıcıda komut dosyalarının değerlendirilmesini optimize etmek kuşkusuz karmaşık 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ğerlendirmesini çok sayıda küçük göreve yayar ve böylece ana ileti dizisini engellemek yerine ana iş parçacığına kullanıcı etkileşimlerini daha verimli bir şekilde yönetme becerisi kazandırırsınız.
Özetlemek gerekirse, büyük senaryo değerlendirme görevlerini parçalara ayırmak 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. Bunlar, ana iş parçacığını engelleyen ve kaynakları yoğun olarak kullanan komut dosyası değerlendirme görevlerini başlatır. Bu çalışmayı ayırmak için senaryolarınızı daha fazla<script>
öğesine yayın.- ES modüllerini tarayıcıya yerel olarak yüklemek için
type=module
özelliğinin kullanılması, her bir ayrı modül komut dosyasının değerlendirilmesi için bağımsız görevleri başlatır. - Dinamik
import()
çağrılarını kullanarak ilk paketlerinizin boyutunu küçültün. Bu, paketleyiciler dinamik olarak içe aktarılan her modülü bir "bölme noktası" olarak 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 ödünleşimleri hesaba kattığınızdan emin olun. Büyük komut dosyaları daha iyi sıkıştırılır ancak daha az görevde daha pahalı komut dosyası değerlendirme çalışmaları içerme olasılıkları artar ve tarayıcı önbelleğini geçersiz kılar. Bu da genel olarak daha düşük önbelleğe alma verimliliğine neden olur.
- ES modüllerini paketlemeden yerel olarak kullanıyorsanız başlatma sırasında bunların yüklenmesini optimize etmek için
modulepreload
kaynak ipucunu kullanın. - Her zaman olduğu gibi, mümkün olduğunca az JavaScript gönderin.
Elbette bu, dengeyi sağlayan bir eylemdir ancak dinamik import()
ile komut dosyalarını bölerek ve ilk yükü azaltarak bu önemli başlatma döneminde daha iyi başlangıç performansı elde edebilir ve kullanıcı etkileşimlerini daha iyi karşılayabilirsiniz. Bu sayede INP metriğinde daha iyi puan toplayarak daha iyi bir kullanıcı deneyimi sunabilirsiniz.
Markus Spiske'in Unsplash tarafından hazırlanan lokomotif resim.