Komut dosyası değerlendirmesi ve uzun görevler

Komut dosyalarını yüklerken, tarayıcının bunları yürütmeden önce değerlendirmesi zaman alır ve bu da 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.

Sonraki Boyamayla Etkileşimi (INP) optimize etme söz konusu olduğunda karşılaşacağınız önerilerin çoğu, etkileşimlerin kendisini optimize etmek olacaktır. Örneğin, uzun görevleri optimize etme kılavuzunda, setTimeout, isInputPending ve benzeri teknikler ele alınmaktadır. Bu teknikler uzun görevlerden kaçınarak ana iş parçacığı biraz nefes alma alanı sağladığı için yararlıdır. Böylece tek bir uzun görev için beklemek yerine, etkileşimler ve diğer aktiviteler için daha fazla fırsat ortaya çıkabilir.

Peki, komut dosyalarının kendisinin yüklenmesinden kaynaklanan 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ğerlendirmesi tarafından başlatılan görevleri nasıl ele aldığı keşfedilecek ve ana iş parçanızın, sayfa yüklenirken kullanıcı girişlerine daha duyarlı olabilmesi için komut dosyası değerlendirme çalışmasını bölmek amacıyla neler yapabileceğinize bakacağız.

Komut dosyası değerlendirme nedir?

Çok sayıda JavaScript gönderen bir uygulamanın profilini oluşturduysanız bunun nedeninin Komut Dosyasını Değerlendir olarak etiketlenmiş uzun görevlerle karşılaştığını fark etmiş olabilirsiniz.

Komut dosyası değerlendirme işlevi, Chrome Geliştirici Araçları'nın performans profil aracında görselleştirildiği şekilde çalışır. Bu iş, başlatma sırasında ana iş parçacığının kullanıcı etkileşimlerine yanıt verme özelliğini engelleyen uzun bir göreve neden olur.
Komut dosyası değerlendirme işlevi, Chrome Geliştirici Araçları'ndaki performans profil aracında gösterildiği şekilde çalışır. Bu durumda söz konusu iş, ana iş parçacığının kullanıcı etkileşimlerini sağlayan görevler de dahil olmak üzere diğer işleri almasını engelleyen uzun bir göreve neden olmak için yeterli olur.

JavaScript, yürütülmeden hemen önce derlendiği için komut dosyası değerlendirmesi, tarayıcıda JavaScript'in yürütülmesi için gerekli bir parçadır. Bir komut dosyası değerlendirildiğinde öncelikle hatalara karşı ayrıştırılır. Ayrıştırıcı hata bulamazsa komut dosyası bayt kodunda derlenir ve yürütmeye devam edebilir.

Kullanıcılar, sayfa ilk oluşturulduktan kısa bir süre sonra sayfayla etkileşim kurmaya çalışabileceğinden, gerekli olsa da komut dosyası değerlendirmesi sorunlu olabilir. Ancak bir sayfanın oluşturulmuş olması, sayfanın yüklenmenin 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. İstenen etkileşimin şu anda gerçekleşebileceğine dair bir garanti olmasa da (söz konusu etkileşimden sorumlu bir komut dosyası henüz yüklenmemiş olabilir), hazır JavaScript'e bağlı etkileşimler olabilir veya etkileşim tamamen JavaScript'e bağlı olmayabilir.

Senaryolar ve bunları değerlendiren görevler arasındaki ilişki

Komut dosyası değerlendirmesinden sorumlu görevlerin nasıl başlatıldığı, yüklediğiniz komut dosyasının normal bir <script> öğesi aracılığıyla yüklenmesine veya bir komut dosyasının type=module içeren modül olmasına göre farklılık gösterir. Tarayıcılar işleri farklı şekilde ele alma eğiliminde olduğundan, başlıca tarayıcı motorlarının komut dosyası değerlendirmesini nasıl ele aldığına odaklanacağız. Bu durumda, komut dosyası değerlendirme davranışlarının farklı olduğu noktalar üzerinde duracağız.

<script> öğesine sahip komut dosyaları yükleniyor

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, ayrıştırılabilmesi, derlenebilmesi ve yürütülebilmesi amacıyla istenen komut dosyasını değerlendirmek 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 çalışması için gereken her şeyi tek bir komut dosyasında gruplandıracak ş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, bu şart 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 ayrı, daha küçük komut dosyaları yükleyebilirsiniz.

Sayfa yükleme sırasında her zaman JavaScript'i mümkün olduğunca az yüklemeye çalışmanız gerekse de, komut dosyalarınızı bölmeniz, ana iş parçacığını engelleyebilecek büyük tek bir görev yerine, ana iş parçacığını hiç engellemeyecek veya en azından başlangıçtan daha az sayıda küçük görev elde etmenizi sağlar.

Chrome Geliştirici Araçları&#39;nın performans profil aracında görselleştirilmiş şekilde komut dosyası değerlendirmesini içeren birçok görev. Daha 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. Bu da ana iş parçacığının kullanıcı girişine daha hızlı yanıt vermesine olanak tanır.
Sayfanın HTML'sinde birden fazla <script> öğesinin olması sonucunda, 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 yerine ana ileti dizisini engelleme olasılığı daha yüksektir.

Komut dosyası değerlendirmesi için görevleri bölme işlemini, etkileşim sırasında çalışan etkinlik geri çağırmaları sırasında elde edilen getiriye benzer şekilde düşünebilirsiniz. Ancak komut dosyası değerlendirmesinde sonuç veren mekanizma, yüklediğiniz JavaScript'i ana iş parçacığını engelleme olasılığından daha az sayıda büyük komut dosyası yerine birden çok küçük komut dosyasına böler.

<script> öğesine ve type=module özelliğine sahip komut dosyaları yükleniyor

ES modülleri artık <script> öğesinde type=module özelliğiyle tarayıcıda yerel olarak yüklenebilir. Komut dosyası yüklemeye yönelik bu yaklaşım, özellikle haritaları içe aktarma ile birlikte kullanıldığında geliştirici deneyiminde, üretimde kullanılmak üzere kodu dönüştürmek zorunda kalmama gibi bazı avantajlar sağlar. Ancak komut dosyalarının bu şekilde yüklenmesi, görevlerin tarayıcıdan tarayıcıya değişebileceğini gösterir.

Chromium tabanlı tarayıcılar

Chrome gibi tarayıcılarda (veya bu eklentiden türetilen tarayıcılarda), type=module özelliği kullanılarak ES modüllerinin yüklenmesi, type=module özelliğini kullanmadığınızda normalde göreceğinizden farklı türde görevler oluşturur. Örneğin, her modül komut dosyası için Derle modülü etiketli etkinlik içeren bir görev çalışır.

Modül derlemesi, Chrome Geliştirici Araçları&#39;nda görselleştirildiği gibi birden fazla görevde çalışır.
Chromium tabanlı tarayıcılarda modül yükleme davranışı. Her modül komut dosyası, değerlendirmeden önce içeriklerini derlemek için bir Compile modül çağrısı oluşturur.

Modüller derlendikten sonra, bunlarda çalıştırılacak kodlar Modülleri değerlendir etiketli etkinliği başlatır.

Chrome Geliştirici Araçları&#39;nın performans panelinde görselleştirilmiş bir modülün tam zamanında değerlendirilmesi.
Bir modülde bulunan kod çalıştığında bu modül tam zamanında değerlendirilir.

Bunun etkisi, 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örevlerin yönetilmesi açısından bariz bir kazanımdır. Ancak sonuçta ortaya çıkan modül değerlendirme çalışması, yine de kaçınılmaz bir maliyete neden olduğunuz anlamına gelir. Mümkün olduğunca az JavaScript göndermeniz gerekse de, ES modüllerini (tarayıcıdan bağımsız olarak) kullanmak aşağıdaki avantajları sağlar:

  • Tüm modül kodu otomatik olarak katı modda çalıştırılır. Bu mod, JavaScript motorlarının, katı olmayan bir bağlamda gerçekleştirilmesi mümkün olmayan 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çin type=module ile yüklenen komut dosyalarında async ö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, teorik olarak diğer modüllere yalnızca statik import ifadelerinden oluşan tek bir üst düzey modül yükleyebileceğiniz ve yüklenen her modülün değerlendirilmesi için ayrı bir ağ isteği ve görevi gerekeceği anlamına gelir.

Dinamik import() ile komut dosyaları yükleniyor

Dinamik import(), komut dosyalarını yüklemenin başka bir yöntemidir. ES modülünün üstünde olması gereken statik import ifadelerinin aksine dinamik import() çağrısı, isteğe bağlı bir şekilde JavaScript parçası yüklemek için komut dosyasının herhangi bir yerinde görünebilir. Bu tekniğe kod bölme denir.

INP'yi iyileştirmek söz konusu olduğunda, dinamik import() iki avantaj sağlar:

  1. Daha sonra yüklenmeye ertelenen modüller, başlatma sırasında yüklenen JavaScript miktarını azaltarak ana iş parçacığı anlaşmazlığını azaltır. Bu, ana ileti dizisini serbest bırakarak kullanıcı etkileşimlerine daha duyarlı olmasını sağlar.
  2. Dinamik import() çağrıları yapıldığında her çağrı, her bir modülün derlemesini ve değerlendirmesini etkin bir şekilde kendi görevine ayırır. Elbette çok büyük bir modül yükleyen dinamik import(), oldukça büyük bir komut dosyası değerlendirme görevi başlatır ve 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 yeteneğini etkileyebilir. Bu nedenle, mümkün olduğunca az JavaScript yüklemeniz yine de çok önemlidir.

Dinamik import() çağrıları, başlıca tarayıcı motorlarının tümünde benzer şekilde davranır: Sonuçta ortaya çıkan komut dosyası değerlendirme görevleri, dinamik olarak içe aktarılan modüllerin miktarıyla aynı olur.

Bir web çalışanında komut dosyaları yükleme

Web çalışanları, JavaScript'in özel 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 iş parçacığının tıkanıklığını azaltır ve ana ileti dizisinin kullanıcı etkileşimlerine daha duyarlı tutulmasına yardımcı olabilir.

Web çalışanları, ana iş parçacığı çalışmasını azaltmanın yanı sıra, çalışan bağlamında kullanılacak harici komut dosyalarını importScripts veya modül çalışanlarını destekleyen tarayıcılardaki statik import ifadeleri aracılığıyla yükleyebilir. Sonuçta bir web çalışanı tarafından istenen herhangi bir komut dosyası ana iş parçacığı dışında değerlendirilir.

Ödünler ve dikkat edilmesi gereken noktalar

Komut dosyalarınızı daha küçük dosyalara bölmek, daha az sayıda, çok daha büyük dosyalar yüklemek yerine uzun görevlerin sınırlandırılmasına yardımcı olur. Ancak, komut dosyalarını nasıl böleceğinize karar verirken bazı şeyleri dikkate almak önemlidir.

Sıkıştırma verimliliği

Komut dosyalarını ayırırken sıkıştırma önemli bir faktördür. Komut dosyaları küçüldüğünde sıkıştırma daha az etkili hale gelir. Büyük komut dosyaları, sıkıştırmadan çok daha fazla yarar sağlar. 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 başlatma sırasında daha iyi etkileşim sağlamak için komut dosyalarını yeterince daha küçük parçalara ayırmanızı sağlamak için biraz dengelemek gerekir.

Paketleyiciler, web sitenizin bağımlı olduğu komut dosyalarının çıktı boyutunu yönetmek için ideal araçlardır:

  • Webpack söz konusu olduğunda, sahip olduğu SplitChunksPlugin eklentisi yardımcı olabilir. Öğe boyutlarını yönetmenize yardımcı olacak seçenekler için SplitChunksPlugin dokümanlarına göz atın.
  • Toplayıcı ve esbuild gibi diğer paketleyiciler için komut dosyası boyutlarını, kodunuzda dinamik import() çağrılarını kullanarak yönetebilirsiniz. Webpack'in yanı sıra bu paketleyiciler de dinamik olarak içe aktarılan öğeyi otomatik olarak kendi dosyasına ayırır ve böylece başlangıçtaki paket boyutlarının daha büyük olmasını önler.

Önbelleği geçersiz kılma

Önbelleğin geçersiz kılınması, bir sayfanın yinelenen ziyaretlerde ne kadar hızlı yüklendiği konusunda büyük bir rol oynar. Büyük, monolitik komut dosyası paketleri gönderdiğinizde, tarayıcı önbelleğine alma açısından dezavantajlı bir konumda olursunuz. Bunun nedeni, paketleri güncelleyerek veya hata düzeltmeleri göndererek birinci taraf kodunuzu güncellediğinizde tüm paketin geçersiz hale gelmesi ve tekrar indirilmesinin gerekmesidir.

Komut dosyalarınızı bölerek komut dosyası değerlendirme çalışmasını daha küçük görevlere bölmekle kalmaz, 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üllerin iç içe yerleştirmenin başlangıç 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ını ifade eder:

// a.js
import {b} from './b.js';

// b.js
import {c} from './c.js';

ES modülleriniz birlikte paketlenmediyse önceki kod bir ağ isteği zinciriyle sonuçlanır: 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 isteği içerir. Bunu önlemenin bir yolu paketleyici kullanmaktır. Ancak paketleyicinizi, komut dosyası değerlendirme çalışmalarını yaymak için komut dosyalarını parçalara 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ı atlatmanın bir başka yolu, ağ isteği zincirlerini önlemek için ES modüllerini önceden önyükleyecek modulepreload kaynak ipucunu kullanmaktır.

Sonuç

Tarayıcıda komut dosyalarının değerlendirmesini optimize etmek hiç kuşkusuz 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şlemini çok sayıda küçük göreve yayar ve böylece ana iş parçacığının ana iş parçacığını engellemek yerine kullanıcı etkileşimlerini daha verimli bir şekilde yönetmesini sağlamış olursunuz.

Özetle, büyük senaryo değerlendirme görevlerini bölmek için yapabileceğiniz bazı şeyler şunlardır:

  • type=module özelliği olmayan <script> öğesini kullanarak komut dosyaları yüklerken, çok büyük komut dosyaları yüklemekten kaçının. Bunlar ana iş parçacığını engelleyen yoğun kaynak kullanan komut dosyası değerlendirme görevlerini başlatır. Bu işi bölmek için komut dosyalarınızı daha fazla <script> öğesine dağıtın.
  • ES modüllerini tarayıcıda yerel olarak yüklemek için type=module özelliği kullanıldığında, her modül komut dosyasının değerlendirilmesi için bağımsız görevler başlatılır.
  • Dinamik import() çağrılarını kullanarak ilk paketlerinizin boyutunu küçültün. Paketleyiciler dinamik olarak içe aktarılan her modülü bir "bölünme noktası" olarak değerlendireceği ve bunun sonucunda, dinamik olarak içe aktarılan her modül için ayrı bir komut dosyası oluşturulacağından bu yöntem paketleyicilerde de işe yarar.
  • Sıkıştırma verimliliği ve önbelleği geçersiz kılma gibi artımları hesaba kattığınızdan emin olun. Daha büyük komut dosyaları daha iyi sıkıştırılır ancak büyük olasılıkla daha az sayıda görevde daha pahalı komut dosyası değerlendirme çalışmaları yaparak tarayıcı önbelleğinin geçersiz kılınmasına yol açarak önbelleğe alma verimliliğini düşürür.
  • ES modüllerini paket halinde sunmadan 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 kodu gönderin.

Elbette bunu dengelemek gerekir. Ancak komut dosyalarını bölerek ve dinamik import() ile ilk yükü azaltarak başlatma performansını iyileştirebilir ve bu önemli başlatma döneminde kullanıcı etkileşimlerine daha iyi uyum sağlayabilirsiniz. Bu sayede INP metriğinde daha iyi puan alabilir ve daha iyi bir kullanıcı deneyimi sunabilirsiniz.

Unsplash'tan Markus Spiske'nin lokomotif resmi.