Yayınlanma tarihi: 31 Mart 2014
Kritik oluşturma yolu performans darboğazlarını tespit etmek ve çözmek için yaygın hatalardan haberdar olmanız gerekir. Yaygın performans kalıplarını belirlemenize yardımcı olacak rehberli tur, sayfalarınızı optimize etmenize yardımcı olur.
Kritik oluşturma yolunu optimize etmek, tarayıcının sayfayı mümkün olduğunca hızlı bir şekilde boyamasına olanak tanır: Daha hızlı sayfalar, daha yüksek etkileşim, daha fazla görüntülenen sayfa ve dönüşümde artış anlamına gelir. Ziyaretçinin boş ekranı görüntüleme süresini en aza indirmek için hangi kaynakların ve hangi sırayla yükleneceğini optimize etmemiz gerekir.
Bu süreci açıklamaya yardımcı olmak için mümkün olan en basit durumdan başlayın ve sayfamızı ek kaynaklar, stiller ve uygulama mantığı içerecek şekilde kademeli olarak oluşturun. Bu süreçte her destek kaydını optimize ederiz ve nerede sorun yaşanabileceğini görürüz.
Şimdiye kadar, kaynak (CSS, JS veya HTML dosyası) işlenmeye hazır hale geldikten sonra tarayıcıda neler olduğuna odaklandık. Kaynağı önbellekten veya ağdan getirmek için gereken süreyi yoksaydık. Aşağıdakileri varsayacağız:
- Sunucuya yapılan bir ağ gidiş dönüşünün (yayma gecikmesi) maliyeti 100 ms'dir.
- Sunucu yanıt süresi, HTML dokümanı için 100 ms, diğer tüm dosyalar için 10 ms'dir.
Hello world deneyimi
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Critical Path: No Style</title>
</head>
<body>
<p>Hello <span>web performance</span> students!</p>
<div><img src="awesome-photo.jpg" /></div>
</body>
</html>
Temel HTML işaretlemesi ve tek bir resimle başlayın; CSS veya JavaScript olmadan. Ardından, Chrome Geliştirici Araçları'nda Ağ panelini açın ve ortaya çıkan kaynak şelalesini inceleyin:
Beklenen gibi, HTML dosyasının indirilmesi yaklaşık 200 ms sürdü. Mavi çizginin şeffaf kısmının, tarayıcının ağda herhangi bir yanıt baytı almadan beklediği süreyi, katı kısmının ise ilk yanıt baytları alındıktan sonra indirme işleminin tamamlanma süresini temsil ettiğini unutmayın. HTML indirme işlemi küçüktür (<4K), bu nedenle dosyanın tamamını almak için tek bir gidiş dönüş işlemi yeterlidir. Sonuç olarak, HTML dokümanının getirilmesi yaklaşık 200 ms sürer; bu sürenin yarısı ağ üzerinde, diğer yarısı ise sunucu yanıtını bekler.
HTML içeriği kullanıma sunulduğunda tarayıcı baytları ayrıştırır, jetonlara dönüştürür ve DOM ağacını oluşturur. DevTools'un, DOMContentLoaded etkinliğinin süresini alt kısımda (216 ms) kolayca raporladığını ve bunun mavi dikey çizgiye de karşılık geldiğini unutmayın. HTML indirme işleminin sonu ile mavi dikey çizgi (DOMContentLoaded) arasındaki boşluk, tarayıcının DOM ağacını oluşturması için gereken süredir (bu örnekte yalnızca birkaç milisaniye).
"Mükemmel fotoğrafımızın" domContentLoaded
etkinliğini engellemediğini görebilirsiniz. Oluşturma ağacını oluşturabildiğimizi, hatta sayfadaki her bir öğeyi beklemeden sayfayı boyayabildiğimizi görüyoruz: Hızlı ilk boyamayı sunmak için tüm kaynaklar kritik öneme sahip değildir. Aslında, kritik oluşturma yolundan bahsettiğimizde genellikle HTML işaretlemesinden, CSS'den ve JavaScript'ten bahsederiz. Resimler sayfanın ilk kez oluşturulmasını engellemez, ancak resimlerin mümkün olan en kısa sürede boyanmasını sağlamaya da çalışmamız gerekir.
Bununla birlikte, load
etkinliği (onload
olarak da bilinir) resimde engellenir: DevTools, onload
etkinliğini 335 ms olarak raporlar. onload
etkinliğinin, sayfanın ihtiyaç duyduğu tüm kaynakların indirilip işlendiği noktayı işaret ettiğini unutmayın. Bu noktada, tarayıcıda yükleme spinner'ı (şelaledeki kırmızı dikey çizgi) dönmeyi durdurabilir.
JavaScript ve CSS'yi dahil etme
"Hello World deneyimi" sayfamız basit görünüyor ancak işin mutfağında pek çok şey var. Uygulamada, yalnızca HTML'den daha fazlasına ihtiyacımız olacaktır: Sayfamıza biraz etkileşim eklemek için bir CSS stil sayfasına ve bir veya daha fazla komut dosyasına sahip olmamız olasıdır. Ne olacağını görmek için her ikisini de ekleyin:
<!DOCTYPE html>
<html>
<head>
<title>Critical Path: Measure Script</title>
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link href="style.css" rel="stylesheet" />
</head>
<body onload="measureCRP()">
<p>Hello <span>web performance</span> students!</p>
<div><img src="awesome-photo.jpg" /></div>
<script src="timing.js"></script>
</body>
</html>
JavaScript ve CSS eklemeden önce:
JavaScript ve CSS ile:
Harici CSS ve JavaScript dosyaları eklemek şelalemize iki ek istek ekler. Bu isteklerin tümü tarayıcı tarafından yaklaşık olarak aynı anda gönderilir. Ancak artık domContentLoaded
ile onload
etkinlikleri arasında çok daha küçük bir zaman farkı olduğunu unutmayın.
Ne oldu?
- Düz HTML örneğimizden farklı olarak, CSSOM'yi oluşturmak için CSS dosyasını getirmemiz ve ayrıştırmamız gerekir. Ayrıca, oluşturma ağacını oluşturmak için hem DOM hem de CSSOM'ye ihtiyacımız vardır.
- Sayfa, JavaScript dosyasını engelleyen bir ayrıştırıcı da içerdiğinden
domContentLoaded
etkinliği, CSS dosyası indirilip ayrıştırılana kadar engellenir: JavaScript, CSSOM'u sorgulayabileceğinden JavaScript'i çalıştırabilmemiz için CSS dosyası indirilene kadar CSS dosyasını engellememiz gerekir.
Harici komut dosyamızı satır içi komut dosyasıyla değiştirirsek ne olur? Komut dosyası doğrudan sayfaya yerleştirilmiş olsa bile tarayıcı, CSSOM oluşturulana kadar komut dosyasını yürütemez. Özetle, satır içi JavaScript de ayrıştırıcıyı engeller.
Bununla birlikte, CSS'de engellemeye rağmen komut dosyasının satır içi olarak eklenmesi sayfanın daha hızlı oluşturulmasını sağlar mı? Deneyin ve ne olduğunu görün.
Harici JavaScript:
Satır içi JavaScript:
Şu anda bir istek daha azalıyoruz, ancak hem onload
hem de domContentLoaded
saatimiz etkin olarak aynı. Neden? JavaScript'in satır içi veya harici olmasının önemli olmadığını biliyoruz, çünkü tarayıcı komut dosyası etiketine dokunur dokunmaz engeller ve CSSOM oluşturulana kadar bekler. Ayrıca, ilk örneğimizde tarayıcı hem CSS'yi hem de JavaScript'i paralel olarak indirir ve indirme işlemi yaklaşık olarak aynı zamanda tamamlanır. Bu durumda, JavaScript kodunu satır içi olarak yerleştirmek bize pek yardımcı olmaz. Ancak sayfamızın daha hızlı oluşturulmasını sağlayabilecek birkaç strateji vardır.
Öncelikle, tüm satır içi komut dosyalarının ayrıştırıcıyı engellediğini ancak harici komut dosyaları için ayrıştırıcının engellemesini kaldırmak üzere async
özelliğini ekleyebileceğimizi hatırlatmak isteriz. Satır içi ekleme işlemimizi geri alıp bunu deneyin:
<!DOCTYPE html>
<html>
<head>
<title>Critical Path: Measure Async</title>
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link href="style.css" rel="stylesheet" />
</head>
<body onload="measureCRP()">
<p>Hello <span>web performance</span> students!</p>
<div><img src="awesome-photo.jpg" /></div>
<script async src="timing.js"></script>
</body>
</html>
Ayrıştırıcıyı engelleyen (harici) JavaScript:
Eş zamansız (harici) JavaScript:
Çok daha iyi. domContentLoaded
etkinliği, HTML ayrıştırıldıktan kısa bir süre sonra tetiklenir; tarayıcı, JavaScript'i engellemeyeceğini bilir ve başka ayrıştırıcıyı engelleyen komut dosyası olmadığından CSSOM oluşturma işlemi de paralel olarak devam edebilir.
Alternatif olarak, hem CSS'yi hem de JavaScript'i satır içi olarak ekleyebilirdik:
<!DOCTYPE html>
<html>
<head>
<title>Critical Path: Measure Inlined</title>
<meta name="viewport" content="width=device-width,initial-scale=1" />
<style>
p {
font-weight: bold;
}
span {
color: red;
}
p span {
display: none;
}
img {
float: right;
}
</style>
</head>
<body>
<p>Hello <span>web performance</span> students!</p>
<div><img src="awesome-photo.jpg" /></div>
<script>
var span = document.getElementsByTagName('span')[0];
span.textContent = 'interactive'; // change DOM text content
span.style.display = 'inline'; // change CSSOM property
// create a new element, style it, and append it to the DOM
var loadTime = document.createElement('div');
loadTime.textContent = 'You loaded this page on: ' + new Date();
loadTime.style.color = 'blue';
document.body.appendChild(loadTime);
</script>
</body>
</html>
domContentLoaded
süresinin önceki örnekle aynı olduğunu fark edin. JavaScript'imizi asenkron olarak işaretlemek yerine hem CSS'yi hem de JS'yi sayfanın içine yerleştirdik. Bu, HTML sayfamızı çok daha büyük hale getirir ancak avantajı, tarayıcının harici kaynakları almak için beklemesi gerekmemesidir. Her şey sayfanın içindedir.
Gördüğünüz gibi, çok temel bir sayfada bile, kritik oluşturma yolunu optimize etmek önemsiz bir uygulamadır: Farklı kaynaklar arasındaki bağımlılık grafiğini anlamamız, hangi kaynakların "kritik" olduğunu belirlememiz ve bu kaynakları sayfaya eklemek için farklı stratejiler arasından seçim yapmamız gerekir. Bu sorunun tek bir çözümü yoktur. Her sayfa farklıdır. Optimum stratejiyi belirlemek için benzer bir süreci kendi başınıza uygulamanız gerekir.
Bununla birlikte, geri çekilip bazı genel performans kalıplarını belirleyip belirleyemeyeceğimize bakalım.
Performans kalıpları
Olası en basit sayfa yalnızca HTML işaretlemesinden oluşur. CSS, JavaScript veya başka tür kaynaklar bulunmaz. Bu sayfayı oluşturmak için tarayıcının isteği başlatması, HTML dokümanının gelmesini beklemesi, dokümanı ayrıştırması, DOM'u oluşturması ve ardından ekranda oluşturması gerekir:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Critical Path: No Style</title>
</head>
<body>
<p>Hello <span>web performance</span> students!</p>
<div><img src="awesome-photo.jpg" /></div>
</body>
</html>
T0 ile T1 arasındaki süre, ağ ve sunucu işlem sürelerini yakalar. En iyi durumda (HTML dosyası küçükse), yalnızca bir ağ gidiş dönüşü tüm belgeyi getirir. TCP aktarım protokollerinin işleyiş şekli nedeniyle, büyük dosyalar için daha fazla gidiş geliş gerekebilir. Sonuç olarak, en iyi durumda yukarıdaki sayfanın kritik oluşturma yolu bir gidiş dönüş (minimum) içerir.
Şimdi aynı sayfayı harici bir CSS dosyasıyla ele alalım:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link href="style.css" rel="stylesheet" />
</head>
<body>
<p>Hello <span>web performance</span> students!</p>
<div><img src="awesome-photo.jpg" /></div>
</body>
</html>
HTML belgesini almak için tekrar bir ağ gidiş dönüş işlemi gerçekleştiririz. Ardından, alınan işaretleme bize CSS dosyasına da ihtiyacımız olduğunu söyler. Bu, tarayıcının sayfayı ekranda oluşturmadan önce sunucuya geri dönüp CSS'yi alması gerektiği anlamına gelir. Sonuç olarak, bu sayfanın gösterilebilmesi için en az iki gidiş dönüş işlemi gerekir. CSS dosyası birden fazla gidiş dönüş işlemi gerçekleştirebilir. Bu nedenle "minimum" vurgusu yapılmıştır.
Kritik oluşturma yolunu açıklamak için kullandığımız bazı terimler:
- Kritik Kaynak: Sayfanın ilk oluşturulmasını engelleyebilecek kaynak.
- Kritik Yol Uzunluğu: Dönüş sayısını veya tüm kritik kaynakları getirmenin toplam süresini belirtir.
- Kritik Baytlar: Sayfanın ilk oluşturulmasına ulaşmak için gereken toplam bayt sayısıdır. Tüm kritik kaynakların aktarım dosya boyutlarının toplamıdır. Tek bir HTML sayfası içeren ilk örneğimizde tek bir kritik kaynak (HTML dokümanı) vardı. Kritik yol uzunluğu da bir ağ gidiş dönüş işlemine eşitti (dosyanın küçük olduğu varsayılır). Toplam kritik bayt sayısı ise yalnızca HTML dokümanındaki aktarım boyutuydu.
Şimdi bunu önceki HTML ve CSS örneğinin kritik yol özelliklerine göre karşılaştırın:
- 2 kritik kaynak
- Minimum kritik yol uzunluğu için 2 veya daha fazla gidiş dönüş
- 9 KB kritik bayt
Oluşturma ağacını oluşturmak için hem HTML'ye hem de CSS'ye ihtiyacımız vardır. Sonuç olarak hem HTML hem de CSS kritik kaynaklardır: CSS yalnızca tarayıcı HTML belgesini aldıktan sonra getirilir. Bu nedenle kritik yol uzunluğu en az iki gidiş dönüştür. Her iki kaynak da toplam 9 KB kritik bayt içerir.
Şimdi karışıma ek bir JavaScript dosyası ekleyin.
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link href="style.css" rel="stylesheet" />
</head>
<body>
<p>Hello <span>web performance</span> students!</p>
<div><img src="awesome-photo.jpg" /></div>
<script src="app.js"></script>
</body>
</html>
Hem sayfadaki harici bir JavaScript öğesi hem de ayrıştırıcıyı engelleyen (yani kritik) bir kaynak olan app.js
öğesini ekledik. Daha da kötüsü, JavaScript dosyasını yürütmek için CSSOM'u engelleyip beklememiz gerekir. JavaScript'in CSSOM'u sorgulayabileceğini ve bu nedenle style.css
indirilip CSSOM oluşturulana kadar tarayıcının duraklatıldığını unutmayın.
Bununla birlikte, pratikte bu sayfanın "ağ şelalesine" bakarsak hem CSS hem de JavaScript isteklerinin yaklaşık olarak aynı anda başlatıldığını görebilirsiniz. Tarayıcı HTML'yi alır, her iki kaynağı da keşfeder ve her iki isteği de başlatır. Sonuç olarak, önceki resimde gösterilen sayfa aşağıdaki kritik yol özelliklerine sahiptir:
- 3 kritik kaynak
- Minimum kritik yol uzunluğu için 2 veya daha fazla gidiş dönüş
- 11 KB kritik bayt
Şu anda toplamda 11 KB'lık kritik baytlara sahip üç kritik kaynağımız var, ancak CSS ve JavaScript'i paralel olarak aktarabildiğimiz için kritik yol uzunluğumuz hâlâ iki gidiş-dönüştür. Kritik oluşturma yolunuzun özelliklerini anlamak, kritik kaynakları tanımlayabilmek ve ayrıca tarayıcının bu kaynakların getirilmelerini nasıl planlayacağını anlamak anlamına gelir.
Site geliştiricilerimizle sohbet ettikten sonra, sayfamıza dahil ettiğimiz JavaScript'in engellemesi gerekmediğini fark ettik. O sırada, sayfanın oluşturulmasını engellemesi gerekmeyen bazı analizler ve başka kodlar da var. Bu bilgilerle, ayrıştırıcının engellemesini kaldırmak için async
özelliğini <script>
öğesine ekleyebiliriz:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link href="style.css" rel="stylesheet" />
</head>
<body>
<p>Hello <span>web performance</span> students!</p>
<div><img src="awesome-photo.jpg" /></div>
<script src="app.js" async></script>
</body>
</html>
Eşzamansız komut dosyalarının birkaç avantajı vardır:
- Komut dosyası artık ayrıştırıcı engellemesinde değildir ve kritik oluşturma yolunun bir parçası değildir.
- Başka kritik komut dosyası olmadığı için CSS'nin
domContentLoaded
etkinliğini engellemesi gerekmez. domContentLoaded
etkinliği ne kadar erken tetiklenirse diğer uygulama mantığı o kadar erken çalışmaya başlayabilir.
Sonuç olarak, optimize edilmiş sayfamız artık iki kritik kaynağa (HTML ve CSS) geri döndü. Kritik yol uzunluğu minimum iki gidiş dönüş ve toplam 9 KB kritik bayttır.
Son olarak, CSS stil sayfasının yalnızca basılı için gerekli olması durumunda bu nasıl görünürdü?
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link href="style.css" rel="stylesheet" media="print" />
</head>
<body>
<p>Hello <span>web performance</span> students!</p>
<div><img src="awesome-photo.jpg" /></div>
<script src="app.js" async></script>
</body>
</html>
style.css kaynağı yalnızca baskı için kullanıldığı için tarayıcının sayfayı oluşturmak üzere bu kaynağı engellemesi gerekmez. Bu nedenle, DOM oluşturma işlemi tamamlanır tamamlanmaz tarayıcı sayfayı oluşturmak için yeterli bilgiye sahip olur. Sonuç olarak, bu sayfada yalnızca tek bir kritik kaynak (HTML dokümanı) vardır ve minimum kritik oluşturma yolu uzunluğu bir gidiş dönüştür.