Komut dosyası değerlendirmesi ve uzun görevler

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.

Komut dosyası değerlendirmesi, Chrome Geliştirici Araçları'nın performans profilleyicisinde görselleştirildiği şekilde çalışır. Bu işlem, başlangıç sırasında uzun bir görev oluşturur ve ana iş parçacığının kullanıcı etkileşimlerine yanıt verme özelliğini engeller.
Chrome Geliştirici Araçları'ndaki performans profilleyicide gösterildiği gibi komut dosyası değerlendirme çalışması. Bu durumda, iş, ana iş parçacığının kullanıcı etkileşimlerini artıran görevler de dahil olmak üzere başka işler almasını engelleyen uzun bir göreve neden olacak kadar fazladır.

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 hatalar için ayrıştırı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 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.

Chrome Geliştirici Araçları&#39;nın performans profilleyicisinde görselleştirilen komut dosyası değerlendirmesini içeren birden fazla görev. Daha az sayıda büyük komut dosyası yerine birden fazla küçük komut dosyası yüklendiğinde görevlerin uzun görev haline gelme olasılığı azalır. Bu da ana iş parçacığının kullanıcı girişlerine daha hızlı yanıt vermesini sağlar.
Sayfanın HTML'sinde bulunan birden fazla <script> öğesi nedeniyle komut dosyalarını değerlendirmek için birden fazla görev oluşturuldu. Bu, kullanıcılara tek bir büyük komut dosyası paketi göndermekten daha iyidir. Ana iş parçacığının tıkanması daha olasıdır.

Komut dosyası değerlendirmesi için görevleri bölmeyi, etkileşim sırasında çalışan etkinlik geri çağırmalarında veriye geçmeye biraz benzer olarak düşünebilirsiniz. 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.

Chrome DevTools&#39;da görselleştirilen birden fazla görevde modül derleme çalışması.
Chromium tabanlı tarayıcılarda modül yükleme davranışı. Her modül komut dosyası, içeriğini değerlendirmeden önce derlemek için bir Derle modülü çağrısı oluşturur.

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.

Chrome Geliştirici Araçları&#39;nın performans panelinde görselleştirilen bir modülün tam zamanında değerlendirmesi.
Bir modüldeki kod çalıştırıldığında söz konusu modül tam zamanında değerlendirilir.

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çin type=module ile yüklenen komut dosyalarında async özelliğini kullanabilirsiniz.

Safari ve Firefox

Safari ve Firefox'ta yüklenen modüllerin 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:

  1. 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ığı, kullanıcı etkileşimlerine daha duyarlı olabilir.
  2. 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 bir import(), oldukça büyük bir komut dosyası değerlendirmesi görevini başlatır. Bu da etkileşim dinamik import() ç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ıştığı, web işçisindeki kodun ise çalışmadığı için son derece faydalıdır. Bu, ana ileti dizisindeki tıkanıklığı azaltır ve ana ileti dizisinin kullanıcı etkileşimlerine daha duyarlı olmasını sağlayabilir.

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çin SplitChunksPlugin 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ölmezsiniz, 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ı anlamına gelir:

// 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 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.