Tarayıcı önyükleme tarayıcısının ne olduğunu, performansa nasıl yardımcı olduğunu ve nasıl engel olabileceğinizi öğrenin.
Sayfa hızını optimize etmenin gözden kaçan yönlerinden biri de tarayıcının dahili bileşenleri hakkında biraz bilgi sahibi olmayı içerir. Tarayıcılar, performansı artırmak için geliştiriciler olarak yapamadığımız belirli optimizasyonlar yapar, ancak bu optimizasyonlar istemeden engellenmediği sürece geçerlidir.
Anlaşılması gereken dahili tarayıcı optimizasyonlarından biri de tarayıcının önceden yükleme tarayıcısıdır. Bu gönderide, önyükleme tarayıcısının nasıl çalıştığı ve daha da önemlisi, sorun yaşamamak için neler yapabileceğiniz ele alınacaktır.
Önceden yükleme tarayıcısı nedir?
Her tarayıcının, ham işaretlemeyi şifreleyen ve bunu bir nesne modeli olarak işleyen bir birincil HTML ayrıştırıcısı vardır. Tüm bunlar, ayrıştırıcı <link>
öğesiyle yüklenen stil sayfası veya async
ya da defer
özelliği olmayan <script>
öğesiyle yüklenmiş komut dosyası gibi bir engelleyici kaynak bulduğunda duraklayana kadar devam eder.
CSS dosyaları söz konusu olduğunda, stilsiz içeriğin (FOUC) tekrar açılmasını önlemek için hem ayrıştırma hem de oluşturma engellenir. Bu durum, bir sayfanın stile uygulanmamış sürümünün, stil uygulanmadan önce kısa süreliğine görülebilmesi anlamına gelir.
Tarayıcı, defer
veya async
özelliği olmayan <script>
öğeleriyle karşılaştığında sayfanın ayrıştırılmasını ve oluşturulmasını da engeller.
Bunun nedeni, tarayıcının, birincil HTML ayrıştırıcısı hâlâ işini yaparken belirli bir komut dosyasının DOM'da değişiklik yapıp yapmayacağını kesin olarak bilmemesidir. Bu nedenle, engellenen ayrıştırma ve oluşturma işleminin etkileri önemsiz hale gelmesi için JavaScript'inizin belgenin sonunda yüklenmesi sık başvurulan bir uygulamadır.
Bunlar, tarayıcının hem ayrıştırma hem de oluşturmayı engellemesi için geçerli nedenlerdir. Yine de bu önemli adımlardan herhangi birinin engellenmesi, diğer önemli kaynakların keşfedilmesini geciktirerek gösterimi canlı tutabileceği için istenmeyen bir durumdur. Neyse ki tarayıcılar, bu sorunları azaltmak için ön yükleme tarayıcısı adı verilen ikincil bir HTML ayrıştırıcıyı kullanarak ellerinden geleni yaparlar.
Önceden yükleme tarayıcısının rolü spekülatiftir. Diğer bir deyişle, birincil HTML ayrıştırıcısı bunları keşfetmeden önce fırsatçı bir şekilde getirilecek kaynakları bulmak için ham işaretlemeyi inceler.
Önceden yükleme tarayıcısının çalıştığını nasıl anlarsınız?
Önceden yükleme tarayıcısı, oluşturma ve ayrıştırmanın engellenmesi nedeni var. Bu iki performans sorunu hiç var olmadıysa, önyükleme tarayıcısı çok yararlı olmaz. Bir web sayfasının önceden yükleme tarayıcısından yararlanıp yararlanmayacağını anlamanın anahtarı, bu engelleme olgularına bağlıdır. Bunu yapmak için, önyükleme tarayıcısının nerede çalıştığını öğrenmek amacıyla isteklere yapay bir gecikme uygulayabilirsiniz.
Örnek olarak bir stil sayfası kullanarak temel metin ve resimlerden oluşan bu sayfayı ele alalım. CSS dosyaları hem oluşturma hem de ayrıştırma işlemlerini engellediğinden, bir proxy hizmeti aracılığıyla stil sayfası için iki saniyelik yapay bir gecikme uygularsınız. Bu gecikme, önceden yükleme tarayıcısının çalıştığı ağ şelalesinde görülmeyi kolaylaştırır.
Şelalede görebileceğiniz gibi, ön yükleme tarayıcısı oluşturma ve doküman ayrıştırma engellenmişken bile <img>
öğesini bulur. Bu optimizasyon olmadan tarayıcı, engelleme süresi boyunca öğeleri uygun şekilde getiremez ve daha fazla kaynak isteği eşzamanlı değil ardışık olur.
Bu oyuncak örneğiyle birlikte, önyükleme tarayıcısının devre dışı bırakılabileceği bazı gerçek kalıplara ve bunları düzeltmek için neler yapılabileceğine bir göz atalım.
async
komut dosyası eklendi
<head>
sayfanızda aşağıdaki gibi birkaç satır içi JavaScript içeren bir HTML'niz olduğunu varsayalım:
<script>
const scriptEl = document.createElement('script');
scriptEl.src = '/yall.min.js';
document.head.appendChild(scriptEl);
</script>
Yerleştirilen komut dosyaları varsayılan olarak async
şeklindedir. Dolayısıyla bu komut dosyası eklendiğinde, async
özelliği uygulanmış gibi davranır. Diğer bir deyişle, mümkün olan en kısa sürede çalışır ve oluşturmayı engellemez. İdeal gibi, değil mi? Yine de bu satır içi <script>
öğesinin harici bir CSS dosyası yükleyen <link>
öğesinden sonra geldiğini varsayarsanız optimum olmayan bir sonuç alırsınız:
Neler olduğunu burada inceleyelim:
- 0. saniyede ana doküman istenir.
- 1,4.saniyede, gezinme isteğinin ilk baytı gelir.
- 2.0 saniyede CSS ve resim istenir.
- Ayrıştırıcının stil sayfasını yüklemesi ve
async
komut dosyasını ekleyen satır içi JavaScript'in 2, 6.saniyede bu stil sayfasından sonra geldiği için komut dosyasının sağladığı işlev mümkün olan en kısa sürede kullanılamıyor.
Bu, ideal olmayan bir durumdur çünkü komut dosyası isteği ancak stil sayfasının indirilmesi tamamlandıktan sonra gerçekleşir. Bu, komut dosyasının mümkün olan en kısa sürede çalışmasını geciktirir. Buna karşılık, <img>
öğesi sunucu tarafından sağlanan işaretlemede bulunabilir olduğundan önceden yükleme tarayıcısı tarafından keşfedilir.
Peki, komut dosyasını DOM'ye eklemek yerine async
özelliğine sahip normal bir <script>
etiketi kullanırsanız ne olur?
<script src="/yall.min.js" async></script>
Sonuç şöyle olur:
Bu sorunların, rel=preload
kullanılarak çözülebileceği yönünde bazı cazip yaklaşımlar olabilir. Bu yöntem kesinlikle işe yarayacaktır, ancak bazı yan etkileri olabilir. Sonuçta, DOM'ye <script>
öğesi eklememek suretiyle önlenebilecek bir sorunu düzeltmek için neden rel=preload
ürününü kullanmalısınız?
Önceden yükleme, sorunu "düzeltir" ancak yeni bir soruna yol açar: İlk iki demodaki async
komut dosyası, <head>
içinde yüklenmesine rağmen "Düşük" öncelikte yüklenirken, stil sayfası "En Yüksek" öncelikte yüklenir. async
komut dosyasının önceden yüklendiği son demoda, stil sayfası hâlâ "En Yüksek" öncelikte yükleniyor ancak komut dosyasının önceliği "Yüksek" değerine yükseltildi.
Bir kaynağın önceliği artırıldığında tarayıcı ona daha fazla bant genişliği ayırır. Bu, stil sayfası en yüksek önceliğe sahip olsa bile, komut dosyasının yükseltilmiş önceliğinin, bant genişliği çakışmasına neden olabileceği anlamına gelir. Bu durum, bağlantıların yavaşlığında ya da kaynakların çok fazla olduğu durumlarda etkili olabilir.
Bu sorunun yanıtı oldukça basittir: Başlatma sırasında bir komut dosyası gerekirse, DOM içine yerleştirerek önyükleme tarayıcısını bozmayın. <script>
öğesi yerleşiminin yanı sıra defer
ve async
gibi özelliklerle gerektiği şekilde denemeler yapın.
JavaScript ile geç yükleme
Geç yükleme, verileri korumak için sıklıkla kullanılan harika bir yöntemdir. Bununla birlikte, geç yükleme, deyim yerindeyse bazen "ekranın üst kısmındaki" resimlere yanlış bir şekilde uygulanır.
Bu durum, ön yükleme tarayıcısının söz konusu olduğu durumlarda kaynak bulunabilirliğiyle ilgili potansiyel sorunlara yol açar ve bir görüntü referansının bulunması, indirilmesi, kodunun çözülmesi ve sunulması için gereken süreyi gereksiz yere geciktirebilir. Bu resim işaretlemesini örnek alalım:
<img data-src="/sand-wasp.jpg" alt="Sand Wasp" width="384" height="255">
data-
öneki, JavaScript destekli geç yükleyicilerde yaygın bir kalıptır. Resim, görüntü alanına kaydırıldığında geç yükleyici data-
ön ekini kaldırır. Diğer bir deyişle, önceki örnekte data-src
, src
olur. Bu güncelleme, tarayıcıdan kaynağı getirmesini ister.
Bu kalıp, başlatma sırasında görüntü alanındaki resimlere uygulanana kadar sorunlu değildir. Önceden yükleme tarayıcısı, data-src
özelliğini src
(veya srcset
) özelliğiyle aynı şekilde okumadığından resim referansı daha önce keşfedilmez. Daha da kötüsü, resmin yüklenmesi geç yükleyici JavaScript'inin indirilmesi, derlenmesi ve yürütülmesinden sonra gecikir.
Resmin boyutuna bağlı olarak (görüntü alanının boyutuna bağlı olabilir) Largest Contentful Paint (LCP) için aday öğe olabilir. Önceden yükleme tarayıcısı, resim kaynağını tahmine dayalı olarak önceden getiremediğinde(muhtemelen sayfanın stil sayfalarının oluşturmayı engellediği sırada) LCP bu durumdan olumsuz etkilenir.
Çözüm, resim işaretlemesini değiştirmektir:
<img src="/sand-wasp.jpg" alt="Sand Wasp" width="384" height="255">
Bu, önyükleme tarayıcısı resim kaynağını daha hızlı keşfedip getireceğinden, başlatma sırasında görüntü alanındaki resimler için en uygun kalıptır.
Bu basitleştirilmiş örnekte sonuç, yavaş bağlantıda LCP'de 100 milisaniyelik iyileştirme elde edilmesidir. Bu büyük bir gelişme gibi görünmeyebilir ancak çözümün, hızlı bir işaretleme düzeltmesi olduğunu ve çoğu web sayfasının bu örnekler grubundan daha karmaşık olduğunu düşündüğünüzde bu durum geçerlidir. Bu durum, LCP adaylarının diğer pek çok kaynakla bant genişliği için mücadele etmek zorunda kalabileceği anlamına gelir. Bu nedenle, bu tür optimizasyonlar giderek daha önemli hale gelir.
CSS arka plan resimleri
Tarayıcının önceden yükleme tarayıcısının işaretlemeyi taradığını unutmayın. background-image
özelliği tarafından referans verilen resimlerin getirme işlemlerini içerebilecek diğer kaynak türlerini (ör. CSS) taramaz.
HTML gibi tarayıcılar CSS'yi CSSOM olarak bilinen kendi nesne modeliyle işler. CSSOM oluşturulurken harici kaynaklar keşfedilirse bu kaynaklar önceden yükleme tarayıcısı tarafından değil, keşif sırasında istenir.
Sayfanızın LCP adayının CSS background-image
özelliğine sahip bir öğe olduğunu varsayalım. Kaynaklar yüklendiğinde şunlar gerçekleşir:
Bu durumda, önyükleme tarayıcısı müdahale etmediğinden çok bozulmuş olmaz. Yine de sayfadaki bir LCP adayı background-image
CSS mülkünden geliyorsa bu resmi önceden yüklemeniz gerekir:
<!-- Make sure this is in the <head> below any
stylesheets, so as not to block them from loading -->
<link rel="preload" as="image" href="lcp-image.jpg">
Bu rel=preload
ipucu küçük olsa da tarayıcının resmi normalde olduğundan daha kısa sürede keşfetmesine yardımcı olur:
rel=preload
ipucu sayesinde LCP adayı daha erken keşfedilerek LCP süresi kısalır. Bu ipucu sorunu çözmeye yardımcı olsa da resim LCP adayınızın CSS'den yüklenmesi gerekip yüklenmediğini değerlendirmek daha iyi bir seçenek olabilir. <img>
etiketi sayesinde, görüntü alanı için uygun olan bir resmi yükleme konusunda daha fazla kontrole sahip olurken, ön yükleme tarayıcısının bu resmi bulmasına da izin vermiş olursunuz.
Çok fazla kaynağı satır içine alma
Satır içi, bir kaynağı HTML içine yerleştiren bir uygulamadır. <style>
öğelerinde stil sayfalarını, <script>
öğelerindeki komut dosyalarını ve base64 kodlamasını kullanarak neredeyse diğer tüm kaynakları satır içine alabilirsiniz.
Kaynakları satır içine almak, kaynak için ayrı bir istek yapılmadığından bunları indirmekten daha hızlı olabilir. Doğrudan dokümanın içindedir ve anında yüklenir. Ancak, önemli dezavantajlar mevcuttur:
- HTML'nizi önbelleğe almıyorsanız ve HTML yanıtı dinamikse bunu da yapamazsınız. Satır içi kaynaklar hiçbir zaman önbelleğe alınmaz. Satır içi kaynaklar yeniden kullanılamadığından bu durum performansı etkiler.
- HTML'yi önbelleğe alabilseniz bile, satır içi kaynaklar dokümanlar arasında paylaşılmaz. Bu, önbelleğe alınıp bir kaynağın tamamında yeniden kullanılabilecek harici dosyalara kıyasla önbelleğe alma verimliliğini azaltır.
- Satır içi değeri çok fazla alırsanız bu fazladan, satır içi içeriğin indirilmesi daha uzun süreceği için ön yükleme tarayıcısının, dokümanın sonraki bölümlerinde kaynakları keşfetmesini geciktirirsiniz.
Örnek olarak bu sayfayı ele alalım. Bazı durumlarda LCP adayı, sayfanın üst kısmındaki resimdir ve CSS, bir <link>
öğesi tarafından yüklenen ayrı bir dosyadadır. Sayfada ayrıca CSS kaynağından ayrı dosyalar olarak istenen dört web yazı tipi de kullanılmaktadır.
Şimdi CSS ve tüm yazı tipleri base64 kaynakları olarak satır içine alınırsa ne olur?
Satır içi işlemin etkisi, bu örnekte LCP ve genel olarak performans için olumsuz sonuçlar doğurur. Sayfanın hiçbir şeyi satır içine almayan sürümü, LCP görüntüsünü yaklaşık 3,5 saniye içinde boyuyor. Her şeyi satır içine alan sayfa, 7 saniyeden biraz daha uzun bir süre LCP resmini boyamaz.
Burada yalnızca ön yükleme tarayıcısından çok daha fazlası bulunuyor. Base64, ikili kaynaklar için verimsiz bir biçim olduğundan yazı tiplerini satır içine almak çok iyi bir strateji değildir. Önemli bir başka faktör de harici yazı tipi kaynaklarının, CSSOM tarafından gerekli olmadığı sürece indirilmemesidir. Bu yazı tipleri base64 olarak satır içine alındığında geçerli sayfa için gerekli olsun veya olmasın, indirilir.
Önceden yükleme bazı şeyleri iyileştirebilir mi? Elbette. LCP resmini önceden yükleyip LCP süresini azaltabilirsiniz. Ancak potansiyel olarak önbelleğe alınamayan HTML'nizi satır içi kaynaklarla şişirmek başka olumsuz performans sonuçları da doğurur. İlk Zengin İçerikli Boyama (FCP) de bu kalıptan etkilenir. Hiçbir şeyin satır içine alınmadığı sayfa sürümünde FCP yaklaşık 2, 7 saniyedir. Her şeyin satır içine yerleştirildiği sürümde FCP yaklaşık 5, 8 saniyedir.
Öğeleri, özellikle de base64 kodlu kaynakları HTML içine satır içine alırken çok dikkatli olun. Çok küçük kaynaklar dışında genellikle önerilmez. Mümkün olduğunca az satır içine alın çünkü çok fazla satır içine almak ateşle oynamaktır.
İstemci tarafı JavaScript ile işaretleme oluşturma
JavaScript sayfa hızını kesinlikle etkiler. Geliştiriciler etkileşim sağlamak için bu teknolojiye güvenmenin yanı sıra, içerikleri kendi başlarına yayınlamak için de bu teknolojiye güvenme eğilimindeler. Bu, bazı açılardan geliştirici deneyimini iyileştirse de geliştiriciler için her zaman kullanıcılara fayda sağlamaz.
Önceden yükleme tarayıcısını geçersiz kılabilecek kalıplardan biri, işaretlemeyi istemci tarafı JavaScript'le oluşturmaktır:
İşaretleme yükleri tarayıcıda JavaScript'in içine yerleştirilip tamamen tarayıcıda oluşturulduğunda, bu işaretlemedeki kaynaklar önceden yükleme tarayıcısı tarafından etkin bir şekilde görünmez olur. Bu, önemli kaynakların keşfedilmesini geciktirerek LCP'yi kesinlikle etkiler. Bu örneklerde, LCP resmi isteği, JavaScript'in görünmesini gerektirmeyen, sunucu tarafından oluşturulmuş eşdeğer deneyimle karşılaştırıldığında önemli ölçüde gecikir.
Bu, bu makalenin odağından biraz farklı olsa da işaretleme oluşturmanın istemci üzerindeki etkileri, önceden yükleme tarayıcısını yenmenin çok ötesine geçer. Birincisi, gerekli olmayan bir deneyimi desteklemek için JavaScript'i kullanmak, Sonraki Boyamayla Etkileşimi (INP) etkileyebilecek gereksiz işleme süresine neden olur.
Buna ek olarak, istemcide çok büyük miktarlarda işaretleme oluşturmanın, sunucu tarafından gönderilenle aynı miktarda işaretlemeyle karşılaştırıldığında uzun görevler oluşturma olasılığı daha yüksektir. Bunun nedeni (JavaScript'in içerdiği ekstra işlemlerin yanı sıra), tarayıcıların işaretlemeyi sunucudan akışla aktarması ve oluşturma işlemini uzun görevleri önleyecek şekilde parçalara ayırmasıdır. Öte yandan, istemci tarafından oluşturulan işaretleme, tek bir monolitik görev olarak işlenir ve INP'ye ek olarak Toplam Engelleme Süresi (TBT) veya İlk Giriş Gecikmesi (FID) gibi sayfa duyarlılık metriklerini etkileyebilir.
Bu senaryonun çözümü, şu sorunun cevabına bağlıdır: Sayfanızın işaretlemesinin istemcide oluşturulmak yerine sunucu tarafından sağlanamamasının bir nedeni var mı? Bunun yanıtı "hayır" ise mümkün olduğunda sunucu tarafı oluşturma (SSR) veya statik olarak oluşturulan işaretleme dikkate alınmalıdır çünkü bunlar, önyükleme tarayıcısının önemli kaynakları önceden keşfetmesine ve fırsat bulduğu şekilde getirmesine yardımcı olacaktır.
Sayfanızın, sayfa işaretlemenizin bazı bölümlerine işlevsellik eklemek için JavaScript'e ihtiyacı gerekiyorsa, her ikisinden de en iyi şekilde yararlanmak için SSR ile vanilya JavaScript veya hidrasyon kullanarak bunu yapabilirsiniz.
Önceden yükleme tarayıcısının size yardımcı olmasına yardımcı olun
Önceden yükleme tarayıcısı, başlatma sırasında sayfaların daha hızlı yüklenmesine yardımcı olan son derece etkili bir tarayıcı optimizasyonudur. Önemli kaynakları önceden keşfetme yeteneğini engelleyen kalıplardan kaçınarak geliştirme sürecini kendiniz için basitleştirmiş olmazsınız. Aynı zamanda bazı web vitals verileri de dahil olmak üzere birçok metrikte daha iyi sonuçlar sağlayacak daha iyi kullanıcı deneyimleri oluşturmuş olursunuz.
Özetlemek gerekirse, bu yayından çıkarılmak isteyeceğiniz noktalar şunlardır:
- Tarayıcı ön yükleme tarayıcısı, daha erken getirebileceği kaynakları fırsat bulduğunda keşfetmesi engellenmişse birincil HTML ayrıştırıcısının önünde tarama yapan ikincil bir HTML ayrıştırıcısıdır.
- İlk gezinme isteğinde sunucu tarafından sağlanan işaretlemede bulunmayan kaynaklar, önceden yükleme tarayıcısı tarafından keşfedilemez. Önceden yükleme tarayıcısının geçersiz kılınabileceği yöntemler şunlardır (ancak bunlarla sınırlı değildir):
- JavaScript ile DOM'ye kaynak ekleme (komut dosyaları, resimler, stil sayfaları veya sunucudan gelen ilk işaretleme yükünde daha iyi olacak başka herhangi bir şey olabilir).
- JavaScript çözümü kullanarak ekranın üst kısmındaki resimleri veya iframe'leri geç yükleme.
- İstemcide, JavaScript kullanan belge alt kaynaklarına referanslar içerebilecek işaretleme oluşturuluyor.
- Önceden yükleme tarayıcısı sadece HTML'yi tarar. LCP adayları dahil olmak üzere önemli öğelere referanslar içerebilecek diğer kaynakların (özellikle CSS'nin) içeriklerini incelemez.
Herhangi bir nedenle önceden yükleme tarayıcısının yükleme performansını hızlandırmasını olumsuz etkileyen bir kalıptan kaçınamıyorsanız rel=preload
kaynak ipucunu kullanın. rel=preload
kullanıyorsanız istediğiniz etkiyi sağladığından emin olmak için laboratuvar araçlarında test yapın. Son olarak, çok fazla kaynağı önceden yüklemeyin. Her şeye öncelik verdiğinizde hiçbir şey olmaz.
Kaynaklar
- Komut dosyası tarafından yerleştirilen "eş zamansız komut dosyaları" zararlı olarak kabul edilir
- Tarayıcı Ön Yükleyicisi Sayfaların Daha Hızlı Yüklenmesini Nasıl Sağlıyor?
- Yükleme hızını artırmak için önemli öğeleri önceden yükleyin
- Algılanan sayfa hızını iyileştirmek için ağ bağlantılarını erkenden oluşturma
- Largest Contentful Paint'i optimize etme
Unsplash'tan Mohammad Rahmani 'nin hazırladığı hero resim.