Missed the action at this year's Chrome Dev Summit? Catch up with our playlist on YouTube. Watch now.

Pomiar krytycznej ścieżki renderowania za pomocą interfejsu Navigation Timing

Jeśli czegoś nie da się zmierzyć, nie można tego zoptymalizować. Na szczęście interfejs API Navigation Timing zapewnia nam wszystkie narzędzia do pomiarów na każdym etapie krytycznej ścieżki renderowania.

TL;DR

  • Interfejs Navigation Timing udostępnia sygnatury o wysokiej rozdzielczości czasowej, umożliwiające pomiar krytycznej ścieżki renderowania.
  • Na różnych etapach krytycznej ścieżki renderowania przeglądarka generuje serię zdarzeń, które można następnie przechwycić.

Podstawą każdej solidnej strategii optymalizacji wydajności jest poprawny pomiar i dobre narzędzia. Właśnie to zapewnia interfejs API Navigation Timing.

Interfejs Navigation Timing

Każda z etykiet na powyższym diagramie odpowiada sygnaturze czasowej o wysokiej rozdzielczości. Przeglądarka generuje te sygnatury dla każdej wczytywanej strony. W zasadzie przedstawiamy tutaj tylko niewielką część wszystkich sygnatur czasowych – na razie pomijamy te związane z siecią, ale powrócimy do nich w jednej z następnych lekcji.

Co oznaczają te sygnatury czasowe?

  • domLoading: jest to sygnatura czasowa, od której rozpoczyna się cały proces – przeglądarka właśnie ma rozpocząć parsowanie pierwszych odebranych bajtów dokumentu HTML.
  • domInteractive: sygnalizuje moment, w którym przeglądarka kończy parsowanie wszystkich znaczników HTML i tworzenie modelu DOM.
  • domContentLoaded: sygnalizuje moment, w którym model DOM jest gotowy, arkusze stylów blokujące wykonywanie skryptów JavaScript nie występują, co oznacza, że teraz można (potencjalnie) utworzyć drzewo renderowania.
    • Wiele platform JavaScript czeka z wykonywaniem własnego kodu do pojawienia się tego zdarzenia. Z tej przyczyny przeglądarka przechwytuje sygnatury czasowe EventStart i EventEnd, umożliwiając śledzenia czasu wykonywania.
  • domComplete: jak wskazuje nazwa, ukończono wszystkie procedury przetwarzania i pobieranie wszystkich zasobów na stronie (obrazów itd.) - tzn. wskaźnik postępu wczytywania przestał się obracać.
  • loadEvent: ostatnim etapem wczytywania strony jest wygenerowanie zdarzenia onload, które może wyzwolić wykonywanie dodatkowego kodu aplikacji.

Specyfikacja HTML określa szczegóły odnośnie do występowania każdego ze zdarzeń: kiedy należy je wygenerować, jakie warunki powinny być spełnione i tak dalej. W naszym przypadku skupimy się na kilku kluczowych zdarzeniach związanych z krytyczną ścieżką renderowania:

  • domInteractive sygnalizuje, kiedy gotowy jest model DOM.
  • domContentLoaded zazwyczaj sygnalizuje, kiedy zarówno model DOM, jak i model CSSOM są gotowe.
    • Jeśli nie występują skrypty JavaScript blokujące parsowanie, zdarzenie DOMContentLoaded jest wyzwalane bezpośrednio po zdarzeniu domInteractive.
  • Zdarzenie domComplete informuje o gotowości strony i wszystkich skojarzonych z nią zasobów.

^

<html>
  <head>
    <title>Critical Path: Measure</title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <link href="style.css" rel="stylesheet">
    <script>
      function measureCRP() {
        var t = window.performance.timing,
          interactive = t.domInteractive - t.domLoading,
          dcl = t.domContentLoadedEventStart - t.domLoading,
          complete = t.domComplete - t.domLoading;
        var stats = document.createElement('p');
        stats.textContent = 'interactive: ' + interactive + 'ms, ' +
            'dcl: ' + dcl + 'ms, complete: ' + complete + 'ms';
        document.body.appendChild(stats);
      }
    </script>
  </head>
  <body onload="measureCRP()">
    <p>Hello <span>web performance</span> students!</p>
    <div><img src="awesome-photo.jpg"></div>
  </body>
</html>

Na pierwszy rzut oka powyższy przykład może wydawać się nieco zniechęcający, ale w rzeczywistości jest całkiem prosty. Interfejs API Navigation Timing przechwytuje wszystkie odpowiednie sygnatury czasowe, a nasz kod po prostu czeka na wyzwolenie zdarzenia onload – przypominamy, że zdarzenie onload jest generowane po zdarzeniu domInteractive, domContentLoaded i domComplete – następnie obliczana jest różnica czasu między różnymi sygnaturami czasowymi. Demonstracja interfejsu NavTiming

Na razie powiedzieliśmy już wszystko. Umiemy już śledzić pewne konkretne zdarzenia i tworzyć proste funkcje umożliwiające pomiar czasu. Zwróć uwagę, że kod można zmodyfikować również tak, by zamiast wyświetlać wartości tych pomiarów na stronie wysyłał je do serwera do analizy witryn (Google Analytics wykonuje to automatycznie), co jest świetnym sposobem monitorowania wydajności i znajdowania stron, które skorzystałyby na optymalizacji.