Tarayıcı ön yükleme tarayıcısının ne olduğunu, performansa nasıl yardımcı olduğunu ve bu tarayıcının yolundan nasıl kaçabileceğinizi öğrenin.
Sayfa hızını optimize etmenin göz ardı edilen bir yönü, tarayıcıların iç işleyişiyle ilgili biraz bilgi sahibi olmaktır. Tarayıcılar, performansı geliştirirken geliştiriciler olarak yapamayacağımız şekilde belirli optimizasyonlar yapar. Ancak bu optimizasyonlar yanlışlıkla engellenmediği sürece bu işlemler gerçekleşir.
Anlaşılması gereken dahili tarayıcı optimizasyonlarından biri tarayıcı ön yükleme tarayıcısıdır. Bu yayında, ön yükleme tarayıcısının işleyiş şekli ve daha da önemlisi, tarayıcının önüne geçmekten nasıl kaçınacağınız ele alınacaktır.
Ön yükleme tarayıcı nedir?
Her tarayıcıda, ham işaretlemeyi tokenize eden ve nesne modeli olarak işleyen birincil bir HTML ayrıştırıcı bulunur. Tüm bu işlemler, ayrıştırıcı bir <link>
öğesiyle yüklenen stil sayfası veya async
ya da defer
özelliği olmayan bir <script>
öğesiyle yüklenen komut dosyası gibi bir engelleyici kaynak bulana kadar devam eder.
CSS dosyalarında, stil uygulanmamış içeriğin kısa bir süre gösterilmesi (FOUC) durumunu önlemek için oluşturma işlemi engellenir. Bu durum, bir sayfaya stil uygulanmadan önce sayfanın stil uygulanmamış sürümünün kısa bir süre gösterilmesidir.
Tarayıcı, defer
veya async
özelliği olmayan <script>
öğeleriyle karşılaştığında da sayfanın ayrıştırılmasını ve oluşturulmasını engeller.
Bunun nedeni, birincil HTML ayrıştırıcı hâlâ işini yaparken tarayıcının belirli bir komut dosyasının DOM'u değiştirip değiştirmeyeceğini kesin olarak bilememesidir. Bu nedenle, engellenen ayrıştırma ve oluşturma işlemlerinin etkilerinin marjinal hale gelmesi için JavaScript'inizi dokümanın sonuna yüklemek yaygın bir uygulamadır.
Bunlar, tarayıcının hem ayrıştırmayı hem de oluşturmayı engellemesi için iyi nedenlerdir. Ancak bu önemli adımların herhangi birinin engellenmesi istenmez. Çünkü diğer önemli kaynakların keşfini geciktirerek yayını aksatabilir. Neyse ki tarayıcılar, önceden yükleme tarayıcı adı verilen ikincil bir HTML ayrıştırıcı kullanarak bu sorunları azaltmak için ellerinden geleni yapıyor.
Ön yükleme tarayıcısının rolü spekülatiftir. Diğer bir deyişle, birincil HTML ayrıştırıcı bunları keşfetmeden önce fırsatçı bir şekilde getirilecek kaynakları bulmak için ham işaretlemeyi inceler.
Ön yükleme tarayıcısının ne zaman çalıştığını anlama
Önceden yükleme tarayıcı, engellenen oluşturma ve ayrıştırma işlemi nedeniyle mevcuttur. Bu iki performans sorunu hiç yaşanmamış olsaydı ön yükleme tarayıcı pek yararlı olmazdı. Bir web sayfasının ön yükleme tarayıcısından yararlanıp yararlanamayacağını belirlemenin anahtarı bu engelleme fenomenlerine bağlıdır. Bunu yapmak için, ön yükleme tarayıcısının nerede çalıştığını öğrenmek üzere istekler için yapay bir gecikme uygulayabilirsiniz.
Stil sayfası içeren temel metin ve resimlerin yer aldığı bu sayfayı örnek olarak alın. CSS dosyaları hem oluşturma hem de ayrıştırma işlemlerini engellediği için bir proxy hizmeti aracılığıyla stil sayfası için iki saniyelik yapay bir gecikme eklersiniz. Bu gecikme, ön yükleme tarayıcısının çalıştığı yeri ağ şelalesinde daha kolay görmenizi sağlar.
Şelalede görebileceğiniz gibi, ön yükleme tarayıcı <img>
öğesini oluşturma ve belge ayrıştırma engellenirken bile bulur. Bu optimizasyon olmadan tarayıcı, engelleme süresi boyunca fırsatçı bir şekilde öğe getiremez ve daha fazla kaynak isteği eşzamanlı yerine art arda gelir.
Bu oyuncak örneğini bir kenara bırakarak, ön yükleme tarayıcısının atlatılabileceği bazı gerçek dünya kalıplarına ve bunları düzeltmek için neler yapılabileceğine göz atalım.
Enjekte edilen async
komut dosyaları
<head>
öğenizdeki HTML'de aşağıdaki gibi bazı satır içi JavaScript'lerin bulunduğunu varsayalım:
<script>
const scriptEl = document.createElement('script');
scriptEl.src = '/yall.min.js';
document.head.appendChild(scriptEl);
</script>
Enjekte edilen komut dosyaları varsayılan olarak async
olduğundan bu komut dosyası enjekte edildiğinde async
özelliği uygulanmış gibi davranır. Bu, en kısa sürede çalışacağı ve oluşturmayı engellemeyeceği anlamına gelir. Kulağa iyi geliyor, değil mi? Ancak bu satır içi <script>
öğesinin, harici bir CSS dosyası yükleyen bir <link>
öğesinden sonra geldiğini varsayarsanız en uygun olmayan sonucu alırsınız:
Burada ne olduğunu ayrıntılı şekilde 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ı, stil sayfasını yüklemesi engellendiğinden ve
async
komut dosyasını enjekte eden satır içi JavaScript, bu stil sayfasından sonra 2,6 saniyede geldiğinden, komut dosyasının sağladığı işlev mümkün olan en kısa sürede kullanılamaz.
Komut dosyası isteği yalnızca stil sayfası indirildikten sonra gerçekleştiği için bu yöntem en uygun yöntem değildir. Bu, komut dosyasının en kısa sürede çalışmasını geciktirir. Buna karşılık, <img>
öğesi sunucu tarafından sağlanan işaretlemede bulunabilir olduğu için ön yükleme tarayıcı tarafından bulunur.
Peki komut dosyasını DOM'a yerleştirmek yerine async
özelliğine sahip normal bir <script>
etiketi kullanırsanız ne olur?
<script src="/yall.min.js" async></script>
Sonuç şudur:
Bu sorunların rel=preload
kullanılarak çözülebileceğini öne sürmek cazip gelebilir. Bu yöntem kesinlikle işe yarar ancak bazı yan etkileri olabilir. Sonuçta, DOM'ye <script>
öğesi eklenmeyerek önlenebilen bir sorunu düzeltmek için neden rel=preload
kullanılsın?
Ön yükleme, buradaki sorunu "düzeltir" ancak yeni bir sorun ortaya çıkarır: İlk iki demoda async
komut dosyası, <head>
içinde yüklenmesine rağmen "Düşük" öncelikli olarak yüklenir. Stil sayfası ise "En yüksek" öncelikli olarak yüklenir. async
komut dosyasının önceden yüklendiği son demoda stiller kitabı hâlâ "En yüksek" öncelikte yükleniyor ancak komut dosyasının önceliği "Yüksek" olarak yükseltildi.
Bir kaynağın önceliği yükseltildiğinde tarayıcı buna 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 çekişmesine neden olabileceği anlamına gelir. Bu durum, yavaş bağlantılarda veya kaynakların oldukça büyük olduğu durumlarda bir faktör olabilir.
Yanıt basittir: Başlatma sırasında bir komut dosyasına ihtiyaç duyuluyorsa bu komut dosyasını DOM'e ekleyerek önyükleme tarayıcısını atlatmayın. Gerektiği gibi <script>
öğesi yerleşimi ve defer
ve async
gibi özelliklerle denemeler yapın.
JavaScript ile geç yükleme
Verileri korumak için kullanabileceğiniz mükemmel bir yöntem olan yavaş yükleme, genellikle resimlere uygulanır. Ancak bazen, "ekranın üst kısmında" olan resimlere yavaş yükleme yanlışlıkla uygulanır.
Bu, ön yükleme tarayıcısıyla ilgili kaynak bulunabilirliğiyle ilgili olası sorunlara yol açar ve bir resme ait referansı bulma, indirme, kodunu çözme ve sunma süresini gereksiz yere uzatabilir. Örnek olarak bu resim işaretlemesini ele alalım:
<img data-src="/sand-wasp.jpg" alt="Sand Wasp" width="384" height="255">
data-
ön ekinin kullanılması, JavaScript destekli yavaş yükleyicilerde yaygın bir kalıptır. Görsel, görüntü alanına kaydırıldığında, data-
ön ekinden data-src
kaldırılır. Bu nedenle, önceki örnekte data-src
, src
olur. Bu güncelleme, tarayıcının kaynağı getirmesini ister.
Bu desen, başlangıç sırasında görüntü alanındaki resimlere uygulanana kadar sorun oluşturmaz. Ön yükleme tarayıcı, data-src
özelliğini src
(veya srcset
) özelliğini okuduğu şekilde okumadığından resim referansı daha önce keşfedilmez. Daha da kötüsü, resim, JavaScript'in indirilip derlenip çalıştırılmasının ardından yüklenir.
Görüntünün boyutuna (görüntü alanı boyutuna bağlı olabilir) bağlı olarak Largest Contentful Paint (LCP) için uygun bir öğe olabilir. Ön yükleme tarayıcı, resim kaynağını önceden tahmini olarak getiremediğinde(muhtemelen sayfanın stil sayfalarının oluşturmayı engellediği noktada) LCP olumsuz etkilenir.
Çözüm, resim işaretlemesini değiştirmektir:
<img src="/sand-wasp.jpg" alt="Sand Wasp" width="384" height="255">
Ön yükleme tarayıcı, resim kaynağını daha hızlı keşfedip getireceğinden, bu, başlangıç sırasında görüntü alanındaki resimler için en uygun kalıptır.
Bu basitleştirilmiş örnekte, yavaş bir bağlantıda LCP'de 100 milisaniyelik bir iyileşme elde edilmiştir. Bu, büyük bir iyileştirme 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 örnek gruplarından daha karmaşık olduğunu göz önünde bulundurduğunuzda bu durum önemli bir gelişmedir. Bu, LCP adaylarının bant genişliği için diğer birçok kaynakla rekabet etmesi gerekebileceği anlamına gelir. Bu nedenle, bu tür optimizasyonlar giderek daha önemli hale gelir.
CSS arka plan resimleri
Tarayıcı ön yükleme tarayıcısının işaretleme taradığını unutmayın. background-image
mülkü tarafından başvurulan görsellerin getirilmesini içerebilecek CSS gibi diğer kaynak türlerini taramaz.
Tarayıcılar, HTML gibi CSS'yi CSSOM olarak bilinen kendi nesne modelinde işler. CSSOM oluşturulurken harici kaynaklar bulunursa bu kaynaklar, ön yükleme tarayıcısından değil, bulunduğu sırada istenir.
Sayfanızın LCP adayı, CSS background-image
özelliğine sahip bir öğe olduğunu varsayalım. Kaynaklar yüklenirken aşağıdakiler gerçekleşir:
Bu durumda, ön yükleme tarayıcı devre dışı bırakılmadığı için yenilgiye uğramış sayılmaz. 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üçüktür ancak tarayıcının resmi normalden daha erken keşfetmesine yardımcı olur:
rel=preload
ipucu sayesinde LCP adayı daha erken bulunur ve LCP süresi kısalır. Bu ipucu bu sorunu düzeltmeye yardımcı olsa da daha iyi seçenek, resim LCP adayınızın CSS'den yüklenip yüklenmemesi gerektiğini değerlendirmek olabilir. <img>
etiketi sayesinde, ön yükleme tarayıcısının görseli keşfetmesine izin verirken görüntü alanına uygun bir görsel yükleme konusunda daha fazla kontrole sahip olursunuz.
Çok fazla kaynağı satır içi olarak ekleme
Satır içi, bir kaynağı HTML'nin içine yerleştiren bir uygulamadır. Base64 kodlamayı kullanarak <style>
öğelerine stil sayfaları, <script>
öğelerine komut dosyaları ve neredeyse tüm diğer kaynakları satır içine alabilirsiniz.
Kaynak için ayrı bir istek gönderilmediğinden, kaynakları satır içine yerleştirmek indirmekten daha hızlı olabilir. Doğrudan belgede bulunur ve anında yüklenir. Ancak bu yöntemin önemli dezavantajları vardır:
- HTML'nizi önbelleğe almıyorsanız (ve HTML yanıtı dinamikse bunu yapamazsınız) satır içi kaynaklar hiçbir zaman önbelleğe alınmaz. Satır içi kaynaklar yeniden kullanılamadığı için bu durum performansı etkiler.
- HTML'yi önbelleğe alabilseniz bile satır içi kaynaklar dokümanlar arasında paylaşılmaz. Bu durum, tüm kaynakta önbelleğe alınabilen ve yeniden kullanılabilen harici dosyalara kıyasla önbelleğe alma verimliliğini azaltır.
- Çok fazla içeriği satır içi olarak eklerseniz ek satır içi içeriğin indirilmesi daha uzun süreceği için ön yükleme tarayıcı, belgenin sonraki bölümlerindeki kaynakları keşfetmeyi geciktirir.
Bu sayfayı örnek alalım. Belirli koşullarda 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ılıyor.
CSS ve tüm yazı tipleri Base64 kaynakları olarak satır içi olarak eklenirse ne olur?
Satır içi eklemenin etkisi, bu örnekte LCP ve genel performans açısından olumsuz sonuçlara yol açmaktadır. Sayfanın satır içi hiçbir öğe içermeyen sürümü, LCP resmini yaklaşık 3,5 saniyede boyar. Her şeyi satır içi olarak yerleştiren sayfa, LCP resmini 7 saniyenin biraz üzerine kadar boyamaz.
Burada, ön yükleme tarayıcısından daha fazlası söz konusudur. Base64, ikili kaynaklar için verimsiz bir biçim olduğundan yazı tiplerini satır içine yerleştirmek iyi bir strateji değildir. Etkili olan bir diğer 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çi olarak eklendiğinde, geçerli sayfa için gerekli olup olmadığına bakılmaksızın indirilir.
Ön yükleme yaparak bu durumu iyileştirebilir miyiz? Elbette. LCP resmini önceden yükleyebilir ve LCP süresini kısaltabilirsiniz ancak ön ekteki kaynaklarla önbelleğe alınamayan HTML'nizi şişirmek, performans açısından başka olumsuz sonuçlara da yol açar. İlk Zengin İçerikli Boyama (FCP) da bu kalıptan etkilenir. Sayfanın hiçbir şeyin satır içi yerleştirilmediği sürümünde FCP yaklaşık 2, 7 saniyedir. Her şeyin satır içine alındığı sürümde FCP yaklaşık 5, 8 saniyedir.
Özellikle base64 kodlu kaynaklar olmak üzere öğeleri HTML'ye yerleştirirken çok dikkatli olun. Genel olarak, çok küçük kaynaklar dışında önerilmez. Çok fazla satır içi eklemek riskli olduğundan mümkün olduğunca az satır içi ekleyin.
İşaretleri istemci tarafı JavaScript ile oluşturma
JavaScript'in sayfa hızını etkilediğine şüphe yok. Geliştiriciler yalnızca etkileşim sağlamak için değil, içerik yayınlamak için de bu platforma güveniyor. Bu, bazı açılardan geliştirici deneyimini iyileştirir ancak geliştiricilere sunulan avantajlar her zaman kullanıcılara da sunulmaz.
Ön yükleme tarayıcısını atlatabilecek bir yöntem, işaretlemeyi istemci tarafı JavaScript ile oluşturmaktır:
İşaretçi yükü, tarayıcıda JavaScript tarafından tamamen oluşturulduğunda ve içerdiğinde, bu işaretçideki tüm kaynaklar ön yükleme tarayıcısından görünmez. Bu durum, önemli kaynakların keşfedilmesini geciktirir ve LCP'yi kesinlikle etkiler. Bu örneklerde, LCP resmine yönelik istek, JavaScript'in görünmesini gerektirmeyen eşdeğer sunucu tarafından oluşturulan deneyime kıyasla önemli ölçüde gecikmiştir.
Bu konu, makalenin odak noktasından biraz uzaklaşıyor olsa da işaretlemeyi istemcide oluşturmanın etkileri, ön yükleme tarayıcısını atlatmanın çok ötesine geçer. Örneğin, JavaScript'i gerektirmeyen bir deneyimi desteklemek için JavaScript'i kullanmak, Interaction to Next Paint (INP)'i etkileyebilecek gereksiz işlem süresi oluşturur. İstemcide çok büyük miktarlarda işaretleme oluşturmanın, sunucu tarafından gönderilen aynı miktardaki işaretlemeye kıyasla uzun görevler oluşturma olasılığı daha yüksektir. Bunun nedeni, JavaScript'in gerektirdiği ek işleme dışında, tarayıcıların işaretlemeyi sunucudan aktarması ve oluşturmayı uzun görevleri sınırlayacak şekilde parçalara ayırmasıdır. Öte yandan istemci tarafından oluşturulan işaretleme, tek ve monolitik bir görev olarak ele alınır. Bu da sayfanın INP'sini etkileyebilir.
Bu senaryoda uygulanacak çözüm, şu sorunun yanıtına bağlıdır: Sayfanızın işaretlemesinin istemcide oluşturulması yerine sunucu tarafından sağlanamamasının bir nedeni var mı? Bu sorunun cevabı "hayır" ise sunucu tarafı oluşturma (SSR) veya statik olarak oluşturulmuş işaretleme, mümkün olduğunda dikkate alınmalıdır. Bu, ön yükleme tarayıcısının önemli kaynakları önceden keşfetmesine ve fırsatçı bir şekilde getirmesine yardımcı olur.
Sayfanızın işaretlemesinin bazı bölümlerine işlev eklemek için JavaScript'e ihtiyacı varsa bu işlemi SSR ile, standart JavaScript ile veya her iki dünyanın da en iyisini elde etmek için hidratasyon ile yapabilirsiniz.
Ön yükleme tarayıcısından size yardımcı olmasını sağlama
Ön yükleme tarayıcı, sayfaların başlangıçta daha hızlı yüklenmesine yardımcı olan son derece etkili bir tarayıcı optimizasyonudur. Önemli kaynakları önceden keşfetme özelliğini engelleyen kalıplardan kaçınarak geliştirme sürecini kendiniz için daha basit hale getirmekle kalmaz, bazı web verileri dahil olmak üzere birçok metrikte daha iyi sonuçlar sağlayacak daha iyi kullanıcı deneyimleri de oluşturursunuz.
Özetlemek gerekirse bu gönderiden edinmeniz gereken bilgiler şunlardır:
- Tarayıcı ön yükleme tarayıcısı, daha önce getirebileceği kaynakları fırsatçı bir şekilde keşfetmek için engellenirse birincil tarayıcıdan önce tarayan ikincil bir HTML ayrıştırıcısıdır.
- İlk gezinme isteğinde sunucu tarafından sağlanan işaretlemede bulunmayan kaynaklar, ön yükleme tarayıcı tarafından bulunamaz. Önyükleme tarayıcısını atlatmanın yolları şunlardır (ancak bunlarla sınırlı değildir):
- JavaScript ile DOM'ye kaynak ekleme (ör. komut dosyaları, resimler, stil sayfaları veya sunucudan gelen ilk işaretleme yükünde daha iyi olacak başka herhangi bir şey).
- JavaScript çözümü kullanarak sayfanın üst kısmındaki resimleri veya iFrame'leri gecikmeli yükleme.
- JavaScript kullanarak doküman alt kaynaklarına referanslar içerebilecek işaretlemeyi istemcide oluşturma.
- Ön yükleme tarayıcı yalnızca HTML'yi tarar. LCP adayları da dahil olmak üzere önemli öğelere referanslar içerebilecek diğer kaynakların (özellikle CSS) içeriklerini incelemez.
Herhangi bir nedenle, ön yükleme tarayıcısının yükleme performansını hızlandırma özelliğini olumsuz yönde etkileyen bir kalıbı önleyemiyorsanız rel=preload
kaynak ipucunu kullanabilirsiniz. rel=preload
'yi kullanıyorsanız istediğiniz etkiyi sağladığından emin olmak için laboratuvar araçlarında test edin. Son olarak, her şeye öncelik verdiğinizde hiçbir şeye öncelik vermemiş olursunuz. Bu nedenle, çok fazla kaynağı önceden yüklemeyin.
Kaynaklar
- Komut dosyası enjekte edilen "eş zamansız komut dosyaları" zararlı olarak kabul edildi
- Tarayıcı önceden yükleyicisi sayfaların daha hızlı yüklenmesini nasıl sağlar?
- Yükleme hızını artırmak için kritik öğeleri önceden yükleme
- Algılanan sayfa hızını artırmak için ağ bağlantılarını erkenden kurma
- Largest Contentful Paint'i optimize etme
Mohammad Rahmani tarafından Unsplash'tan alınan lokomotif resim .