Kritik Oluşturma Yolu Performansını Analiz Etme

Ilya Grigorik
Ilya Grigorik

Yayınlanma tarihi: 31 Mart 2014

Kritik oluşturma yolundaki performans sorunlarını belirlemek ve çözmek için sık karşılaşılan tehlikelerin iyi anlaşılması 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 sayfa görüntüleme 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 hangi sırayla yükleneceğini optimize etmemiz gerekir.

Bu süreci açıklamaya yardımcı olması için mümkün olan en basit örnekten başlayın ve ek kaynaklar, stiller ve uygulama mantığını içerecek şekilde sayfamızı aşamalı olarak geliştirin. Bu süreçte her destek kaydını optimize ederiz ve hataların nereden kaynaklanabileceğini görürüz.

Şimdiye kadar özellikle kaynak (CSS, JS veya HTML dosyası) işlenmeye hazır hale geldikten sonra tarayıcıda ne olduğuna odaklandık. Kaynağın önbellekten veya ağdan getirilmesinin ne kadar sürdüğü göz ardı edilmiştir. Aşağıdakileri varsayacağız:

  • Sunucuya gidip dönen bir ağ isteği (yayma gecikmesi) 100 ms sürer.
  • 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>

Deneyin

CSS veya JavaScript olmadan temel HTML işaretleme ve tek bir resimle başlayın. Ardından, Chrome Geliştirici Araçları'nda Ağ panelini açın ve ortaya çıkan kaynak şelalesini inceleyin:

CRP

Beklendiği 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 boyutu küçük (<4K) olduğundan, tüm dosyayı getirmek için tek bir gidiş dönüş yeterlidir. Sonuç olarak, HTML belgesinin getirilmesi yaklaşık 200 ms sürer. Bu sürenin yarısı ağda, diğer yarısı ise sunucu yanıtını beklerken geçer.

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. Geliştirici Araçları'nın, DOMContentLoaded etkinliğinin süresini alt kısımda (216 ms) raporladığını ve bu durumun mavi dikey çizgiye 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).

"Muhteşem fotoğrafımızın" , domContentLoaded etkinliğini engellemedi. Görünüşe göre, sayfadaki her öğeyi beklemeden oluşturma ağacını oluşturabilir ve hatta sayfayı boyayabiliriz: İlk boyamayı hızlı bir şekilde sunmak için tüm kaynakların gerekli olmadığı anlaşılıyor. Aslında kritik oluşturma yolundan bahsederken genellikle HTML işaretlemesi, CSS ve JavaScript'ten bahsediyoruz. Görseller sayfanın ilk oluşturulmasını engellemez. Ancak görsellerin en kısa sürede oluşturulmasını sağlamaya da çalışmalıyız.

Bununla birlikte, load etkinliği (onload olarak da bilinir) resim üzerinde engellendi: Geliştirici Araçları, onload etkinliğini 335 ms.de bildirir. 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 ekleme

"Hello World deneyimimiz" görünse de işin mutfağında birçok şey yaşanıyor. Uygulamada, yalnızca HTML'den daha fazlasına ihtiyacımız olacaktır: Sayfamıza 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 olduğunu görmek için her ikisini de karmaya 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>

Deneyin

JavaScript ve CSS eklemeden önce:

DOM CRP&#39;si

JavaScript ve CSS ile:

DOM, CSSOM ve JS

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 domContentLoaded ve onload etkinlikleri arasında artık çok daha küçük bir zamanlama farkı olduğunu unutmayın.

Ne oldu?

  • Düz HTML örneğimizin aksine, 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 sayfanın içine yerleştirilmiş olsa bile, CSSOM oluşturulana kadar tarayıcı bu dosyayı 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:

DOM, CSSOM, JS

Satır içi JavaScript:

DOM, CSSOM ve satır içi JS

Bir istek daha az gönderiyoruz ancak hem onload hem de domContentLoaded sürelerimiz aslında 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 işlem işlemini geri alın ve bir 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>

Deneyin

Ayrıştırıcıyı engelleyen (harici) JavaScript:

DOM, CSSOM, JS

Eş zamansız (harici) JavaScript:

DOM, CSSOM, eşzamansız JS

Ç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 hem de JavaScript'i satır içine alabilirdik:

<!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>

Deneyin

DOM, satır içi CSS, satır içi JS

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 basit bir sayfada bile kritik oluşturma yolunu optimize etmek basit bir işlem değildir: Farklı kaynaklar arasındaki bağımlılık grafiğini anlamamız, hangi kaynakların "kritik" olduğunu belirlememiz ve bu kaynakları sayfaya dahil etmek 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 diğer kaynak türleri kullanılamaz. Bu sayfayı oluşturmak için tarayıcının isteği başlatması gerekir. HTML belgesinin gelmesini, ayrıştırmasını, DOM'yi derlemesini ve son olarak ekranda oluşturmasını bekleyin:

<!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>

Deneyin

Merhaba dünya CRP

T0 ile T1 arasındaki süre, ağ ve sunucu işleme 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, yukarıdaki sayfada en iyi durumda bir gidiş dönüş (minimum) kritik oluşturma yolu vardır.

Ş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>

Deneyin

DOM + CSSOM CRP

Yine, HTML belgesini getirmek için bir ağ döngüsüne tabi tutuluruz ve daha sonra, alınan işaretleme bize CSS dosyasına da ihtiyacımız olduğunu söyler; Bu, sayfayı ekranda oluşturabilmek için tarayıcının sunucuya geri dönmesi ve 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ı için bir kez daha birden fazla gidiş dönüş sürebilir. Bu nedenle "minimum" öğesi vurgulanır.

Kritik oluşturma yolunu tanımlamak için kullandığımız bazı terimler aşağıda verilmiştir:

  • Kritik Kaynak: Sayfanın ilk kez oluşturulmasını engelleyebilecek kaynak.
  • Kritik Yol Uzunluğu: Gidiş dönüş sayısı veya kritik kaynakların tümünü getirmek için gereken toplam süre.
  • 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ğimiz, tek bir kritik kaynak (HTML belgesi) içeriyordu; kritik yol uzunluğu da bir ağ döngüsüne eşitti (dosyanın küçük olduğu varsayıldığında) ve toplam kritik bayt sayısı yalnızca HTML belgesinin aktarım boyutu kadardı.

Şimdi bunu önceki HTML ve CSS örneğinin kritik yol özellikleriyle karşılaştırın:

DOM + CSSOM CRP

  • 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 döngüdedir. Her iki kaynağın da toplamı 9 KB'lık kritik bayttır.

Şimdi buraya 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>

Deneyin

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.

DOM, CSSOM, JavaScript CRP

Bununla birlikte, pratikte bu sayfanın "ağ şelalesine" baktığımızda, CSS ve JavaScript isteklerinin yaklaşık olarak aynı anda başlatıldığını görürsünüz. 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 yine de iki gidiş-dönüştür. Kritik oluşturma yolunuzun özelliklerini anlamak, kritik kaynakları tanımlayabilmeniz ve ayrıca tarayıcının bu kaynakların getirilmelerini nasıl planlayacağını anlamanız anlamına gelir.

Site geliştiricilerimizle sohbet ettikten sonra, sayfamıza dahil ettiğimiz JavaScript'in engellemesi gerekmediğini fark ettik; içinde, sayfanızın oluşturulmasını engellemesi gerekmeyen bazı analizler ve başka kodlar vardır. Bu bilgiyi kullanarak ayrıştırıcının engellemesini kaldırmak için <script> öğesine async özelliğini 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>

Deneyin

DOM, CSSOM, eşzamansız JavaScript CRP

Eşzamansız komut dosyasının çeşitli avantajları 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ığından CSS'nin domContentLoaded etkinliğini engellemesi gerekmez.
  • domContentLoaded etkinliği ne kadar erken tetiklenirse diğer uygulama mantığı da o kadar erken yürütülmeye başlayabilir.

Sonuç olarak, optimize edilmiş sayfamız artık minimum iki gidiş dönüş uzunluğuna ve toplam 9 KB kritik bayta sahip iki kritik kaynağa (HTML ve CSS) geri döndü.

Son olarak, CSS stil sayfası yalnızca baskı için gerekli olsaydı 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>

Deneyin

DOM, engellemeyen CSS ve eşzamansız JavaScript CRP

style.css kaynağı yalnızca baskı için kullanıldığı için tarayıcının sayfayı oluşturmak üzere bu kaynağı engellemesi gerekmez. Dolayısıyla, 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.

Geri bildirim