Pomiar rzeczywistego wpływu mechanizmów Service Worker na rzeczywistą wydajność

Jedną z najważniejszych zalet skryptów service worker (przynajmniej pod względem wydajności) jest możliwość aktywnego kontrolowania buforowania zasobów. Aplikacja internetowa, która może buforować wszystkie niezbędne zasoby, powinna ładować się znacznie szybciej dla powracających użytkowników. Jak jednak wyglądają korzyści dla rzeczywistych użytkowników? Jak w ogóle to mierzyć?

Aplikacja internetowa Google I/O (w skrócie IOWA) to progresywna aplikacja internetowa, która wykorzystuje większość nowych funkcji oferowanych przez mechanizmy Service Worker, aby zapewniać użytkownikom zaawansowane funkcje przypominające aplikacje. Firma wykorzystała też Google Analytics do zbierania kluczowych danych o skuteczności i wzorcach użytkowania wśród dużej i zróżnicowanej grupy użytkowników.

To studium przypadku pokazuje, jak firma IOWA wykorzystała Google Analytics do uzyskania odpowiedzi na kluczowe pytania dotyczące wydajności i tworzenia raportów na temat rzeczywistego wpływu mechanizmów Service Worker.

Zacznijmy od pytań

Za każdym razem, gdy wdrażasz analitykę w witrynie lub aplikacji, zacznij od określenia pytań, na które będziesz starać się uzyskać odpowiedź w związku ze zbieranymi danymi.

Chociaż chcieliśmy odpowiedzieć na kilka pytań, na potrzeby tego studium przypadku skupmy się na dwóch z najciekawszych.

1. Czy buforowanie skryptu service worker jest bardziej wydajny niż istniejące mechanizmy buforowania HTTP dostępne we wszystkich przeglądarkach?

Już teraz oczekujemy, że strony będą się wczytywać szybciej u powracających użytkowników niż nowi, ponieważ przeglądarki mogą buforować żądania i natychmiast wyświetlać je przy kolejnych wizytach.

Skrypty service worker oferują alternatywne funkcje buforowania, które dają programistom szczegółową kontrolę nad tym, co i jak odbywa się buforowanie. W IOWA zoptymalizowaliśmy implementację mechanizmów Service Worker w taki sposób, aby każdy zasób był zapisywany w pamięci podręcznej, dzięki czemu powracający użytkownicy mogli korzystać z aplikacji w pełni offline.

Czy jednak działanie mogłoby być lepsze niż dotychczasowe działanie przeglądarki? A jeśli tak, to o ile lepiej? 1

2. Jak skrypt service worker wpływa na wczytywanie witryny?

Inaczej mówiąc, jak szybko wydaje się wczytywanie witryny, niezależnie od rzeczywistego czasu wczytywania mierzonego przez tradycyjne dane wczytywania strony?

Odpowiedź na pytania o odczucia w związku z wrażeniami użytkownika oczywiście nie jest łatwym zadaniem, a żadne dane nie oddadzą w ten sposób takiego subiektywnego odczucia. Niektóre dane są lepsze od innych, dlatego trzeba wybrać te właściwe.

Wybór odpowiednich danych

Google Analytics domyślnie śledzi czasy wczytywania stron (za pomocą interfejsu Navigation Timing API) dla 1% użytkowników witryny i udostępnia te dane poprzez takie dane jak Śr. czas wczytywania strony.

Śr. czas wczytywania strony to dobry wskaźnik, który pozwoli odpowiedzieć na pierwsze pytanie, ale nie jest zbyt dobrym danymi do odpowiedzi na drugie pytanie. Z jednej strony zdarzenie load niekoniecznie musi odpowiadać momentowi, w którym użytkownik może wchodzić w interakcję z aplikacją. Poza tym 2 aplikacje o takim samym czasie wczytywania mogą mieć wrażenie innego ich wczytywania. Na przykład witryna z ekranem powitalnym lub wskaźnikiem wczytywania powinna wczytywać się znacznie szybciej niż witryna, która przez kilka sekund wyświetla pustą stronę.

W IOWA zaprezentowaliśmy animację z odliczaniem ekranu powitalnego, która – moim zdaniem – bardzo dobrze służyła rozrywce użytkownika, gdy reszta aplikacji ładowała się w tle. Z tego względu śledzenie czasu, po którym pojawia się ekran powitalny, jest o wiele bardziej uzasadnione jako sposób pomiaru postrzeganej wydajności wczytywania. Aby uzyskać tę wartość, wybraliśmy wskaźnik czas do pierwszego wyrenderowania.

Gdy zdecydowaliśmy się na pytania, na które chcemy odpowiedzieć, i określiliśmy rodzaje danych, które mogą pomóc w uzyskaniu odpowiedzi, przyszedł czas na wdrożenie Google Analytics i rozpoczęcie pomiarów.

Implementacja analityki

Jeśli korzystasz z Google Analytics po raz pierwszy, zapewne znasz zalecany fragment kodu śledzenia JavaScript. Wygląda on następująco:

<script>
window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
ga('create', 'UA-XXXXX-Y', 'auto');
ga('send', 'pageview');
</script>
<script async src="https://www.google-analytics.com/analytics.js"></script>

Pierwszy wiersz powyższego kodu inicjuje globalną funkcję ga() (jeśli jeszcze nie istnieje), a ostatni wiersz pobiera asynchronicznie bibliotekę analytics.js.

Środkowa część składa się z tych 2 wierszy:

ga('create', 'UA-XXXXX-Y', 'auto');
ga('send', 'pageview');

Te 2 polecenia śledzą, jakie strony odwiedzają użytkownicy Twojej witryny, ale niewiele więcej. Jeśli chcesz śledzić dodatkowe interakcje użytkowników, musisz to zrobić samodzielnie.

W ramach konferencji IOWA chcemy śledzić 2 dodatkowe kwestie:

  • Czas, który upływa od momentu rozpoczęcia ładowania strony do pojawienia się pikseli na ekranie.
  • Wskazuje, czy skrypt service worker kontroluje stronę. Dzięki tym informacjom moglibyśmy podzielić nasze raporty na segmenty, aby porównać wyniki ze skryptem service worker i bez niego.

Rejestrowanie czasu do pierwszego wyrenderowania

Niektóre przeglądarki rejestrują dokładny czas, w którym pierwszy piksel został wyrenderowany na ekranie, i udostępniają go deweloperom. Ta wartość w porównaniu z wartością navigationStart ujawnianą za pomocą interfejsu Timing Timing API pozwala nam bardzo dokładnie obliczyć, ile czasu upłynęło od wysłania przez użytkownika prośby o wyświetlenie strony do chwili, gdy zobaczył ją po raz pierwszy.

Jak już wspomnieliśmy, czas do pierwszego wyrenderowania jest ważnym wskaźnikiem, który trzeba zmierzyć, ponieważ to pierwszy moment, przy którym u użytkownika działa Twoja witryna z szybkością wczytywania. To pierwsze wrażenie użytkownika, a dobre pierwsze wrażenie może pozytywnie wpłynąć na wrażenia użytkowników2.

Aby uzyskać pierwszą wartość wyrenderowania w przeglądarkach, które ją wyświetlają, utworzyliśmy funkcję getTimeToFirstPaintIfSupported:

function getTimeToFirstPaintIfSupported() {
  // Ignores browsers that don't support the Performance Timing API.
  if (window.performance && window.performance.timing) {
    var navTiming = window.performance.timing;
    var navStart = navTiming.navigationStart;
    var fpTime;

    // If chrome, get first paint time from `chrome.loadTimes`.
    if (window.chrome && window.chrome.loadTimes) {
      fpTime = window.chrome.loadTimes().firstPaintTime * 1000;
    }
    // If IE/Edge, use the prefixed `msFirstPaint` property.
    // See http://msdn.microsoft.com/ff974719
    else if (navTiming.msFirstPaint) {
      fpTime = navTiming.msFirstPaint;
    }

    if (fpTime && navStart) {
      return fpTime - navStart;
    }
  }
}

Dzięki temu możemy teraz napisać inną funkcję, która wysyła zdarzenie niezwiązane z interakcją z czasem do pierwszego wyrenderowania jako jego wartością3:

function sendTimeToFirstPaint() {
  var timeToFirstPaint = getTimeToFirstPaintIfSupported();

  if (timeToFirstPaint) {
    ga('send', 'event', {
      eventCategory: 'Performance',
      eventAction: 'firstpaint',
      // Rounds to the nearest millisecond since
      // event values in Google Analytics must be integers.
      eventValue: Math.round(timeToFirstPaint)
      // Sends this as a non-interaction event,
      // so it doesn't affect bounce rate.
      nonInteraction: true
    });
  }
}

Po napisaniu obu tych funkcji nasz kod śledzenia wygląda tak:

// Creates the tracker object.
ga('create', 'UA-XXXXX-Y', 'auto');

// Sends a pageview for the initial pageload.
ga('send', 'pageview');

// Sends an event with the time to first paint data.
sendTimeToFirstPaint();

Pamiętaj, że w zależności od tego, kiedy powyższy kod zostanie uruchomiony, piksele mogły już zostać wymalowane na ekranie. Aby mieć pewność, że kod będzie uruchamiany po pierwszym wyrenderowaniu, przełożyliśmy wywołanie na sendTimeToFirstPaint() do czasu zakończenia zdarzenia load. Zdecydowaliśmy się opóźnić wysyłanie wszystkich danych analitycznych do czasu wczytania strony, aby mieć pewność, że żądania te nie będą konkurować z wczytywaniem innych zasobów.

// Creates the tracker object.
ga('create', 'UA-XXXXX-Y', 'auto');

// Postpones sending any hits until after the page has fully loaded.
// This prevents analytics requests from delaying the loading of the page.
window.addEventListener('load', function() {
  // Sends a pageview for the initial pageload.
  ga('send', 'pageview');

  // Sends an event with the time to first paint data.
  sendTimeToFirstPaint();
});

Powyższy kod zgłasza Google Analytics firstpaint razy, ale to tylko połowa sukcesu. Nadal musieliśmy śledzić stan skryptu service worker – w przeciwnym razie nie mogliśmy porównać czasu pierwszego wyrenderowania strony kontrolowanej przez ten skrypt i strony niekontrolowanej.

Ustalam stan skryptu service worker

Aby określić bieżący stan skryptu service worker, utworzyliśmy funkcję, która zwraca jedną z 3 wartości:

  • controlled: skrypt service worker kontroluje stronę. W przypadku IOWA oznacza to również, że wszystkie zasoby zostały zapisane w pamięci podręcznej, a strona działa w trybie offline.
  • supported (obsługiwane): przeglądarka obsługuje mechanizm Service Worker, ale jeszcze nie kontroluje strony. Jest to stan, jakiego oczekujesz w przypadku nowych użytkowników.
  • nieobsługiwany: przeglądarka użytkownika nie obsługuje skryptu service worker.
function getServiceWorkerStatus() {
  if ('serviceWorker' in navigator) {
    return navigator.serviceWorker.controller ? 'controlled' : 'supported';
  } else {
    return 'unsupported';
  }
}

Ta funkcja uzyskała dla nas stan skryptu service worker. Kolejnym krokiem było powiązanie tego stanu z danymi wysyłanymi do Google Analytics.

Śledzenie danych niestandardowych za pomocą wymiarów niestandardowych

Google Analytics domyślnie oferuje wiele sposobów podziału całkowitego ruchu na grupy według atrybutów użytkownika, sesji lub interakcji. Te atrybuty są nazywane wymiarami. Typowe wymiary, które często interesują deweloperów stron internetowych, to Przeglądarka, System operacyjny i Kategoria urządzenia.

Stan skryptu service worker nie jest wymiarem domyślnym w Google Analytics. W Google Analytics możesz jednak tworzyć i definiować własne wymiary niestandardowe.

Na potrzeby IOWA utworzyliśmy niestandardowy wymiar o nazwie Service Worker Status i ustawiliśmy jego zakres na działanie (tj. na interakcję).4 Każdy niestandardowy wymiar utworzony w Google Analytics otrzymuje unikalny indeks w tej usłudze, a w kodzie śledzenia możesz odwoływać się do tego wymiaru. Jeśli np. indeks utworzonego właśnie wymiaru miałby wartość 1, możemy zaktualizować ustawienia logiczne w ten sposób, aby wysyłać zdarzenie firstpaint z uwzględnieniem stanu skryptu service worker:

ga('send', 'event', {
  eventCategory: 'Performance',
  eventAction: 'firstpaint',
  // Rounds to the nearest millisecond since
  // event values in Google Analytics must be integers.
  eventValue: Math.round(timeToFirstPaint)
  // Sends this as a non-interaction event,
  // so it doesn't affect bounce rate.
  nonInteraction: true,

  // Sets the current service worker status as the value of
  // `dimension1` for this event.
  dimension1: getServiceWorkerStatus()
});

To działa, ale powiąże stan skryptu service worker tylko z tym konkretnym zdarzeniem. Stan skryptu service worker jest przydatny w każdej interakcji, dlatego warto go uwzględniać we wszystkich danych wysyłanych do Google Analytics.

Aby uwzględniać te informacje we wszystkich działaniach (np. we wszystkich odsłonach, zdarzeniach itp.), przed wysłaniem jakichkolwiek danych do Google Analytics ustawiamy wartość wymiaru niestandardowego w samym obiekcie tracker.

ga('set', 'dimension1', getServiceWorkerStatus());

Po ustawieniu wartość ta będzie wysyłana ze wszystkimi kolejnymi działaniami w ramach bieżącego wczytania strony. Jeśli użytkownik załaduje stronę ponownie, funkcja getServiceWorkerStatus() prawdopodobnie zwróci nową wartość, która zostanie ustawiona w obiekcie skryptu śledzenia.

Krótka uwaga na temat przejrzystości i czytelności kodu: ponieważ inne osoby oglądające ten kod mogą nie wiedzieć, do czego odnosi się dimension1, najlepiej utworzyć zmienną, która mapuje istotne nazwy wymiarów na wartości, których będzie używać analytics.js.

// Creates a map between custom dimension names and their index.
// This is particularly useful if you define lots of custom dimensions.
var customDimensions = {
  SERVICE_WORKER_STATUS: 'dimension1'
};

// Creates the tracker object.
ga('create', 'UA-XXXXX-Y', 'auto');

// Sets the service worker status on the tracker,
// so its value is included in all future hits.
ga('set', customDimensions.SERVICE_WORKER_STATUS, getServiceWorkerStatus());

// Postpones sending any hits until after the page has fully loaded.
// This prevents analytics requests from delaying the loading of the page.
window.addEventListener('load', function() {
  // Sends a pageview for the initial pageload.
  ga('send', 'pageview');

  // Sends an event with the time to first paint data.
  sendTimeToFirstPaint();
});

Jak już wspomnieliśmy, wysyłanie wymiaru Stan skryptu service worker z każdym działaniem pozwala nam używać go do tworzenia raportów o dowolnych danych.

Jak widać, prawie 85% wszystkich wyświetleń strony na platformie IOWA pochodziło z przeglądarek obsługujących mechanizm Service Worker.

Wyniki: odpowiedzi na pytania

Gdy zaczęliśmy zbierać dane, aby uzyskać odpowiedzi na nasze pytania, mogliśmy je tworzyć w raportach i sprawdzać wyniki. Uwaga: wszystkie widoczne tu dane Google Analytics reprezentują rzeczywisty ruch na stronie IOWA w okresie 16–22 maja 2016 r.

Pierwsze pytanie brzmiało: Czy buforowanie skryptu service worker jest bardziej wydajne niż istniejące mechanizmy buforowania HTTP dostępne we wszystkich przeglądarkach?

Aby odpowiedzieć na to pytanie, stworzyliśmy raport niestandardowy, który analizuje dane Śr. czas wczytywania strony w różnych wymiarach. Te dane idealnie nadają się do odpowiedzi na to pytanie, ponieważ zdarzenie load uruchamia się dopiero po pobraniu wszystkich początkowych zasobów. Bezpośrednio odzwierciedla łączny czas wczytywania wszystkich kluczowych zasobów witryny5.

Wybraliśmy te wymiary:

  • Nasz niestandardowy wymiar Stan skryptu service worker.
  • Typ użytkownika, który wskazuje, czy użytkownik odwiedza witrynę po raz pierwszy, czy też powraca. (Uwaga: nowy użytkownik nie będzie miał żadnych zasobów w pamięci podręcznej – może to oznaczać, że powracający użytkownik).
  • Kategoria urządzenia, która pozwala porównywać wyniki na urządzeniach mobilnych i komputerach.

Aby ograniczyć możliwość, że czynniki niezwiązane z mechanizmami Service Worker zakłócały wyniki dotyczące czasu wczytywania, ograniczyliśmy zapytanie tak, aby obejmowało tylko przeglądarki, które obsługują mechanizm Service Worker.

Jak widać, odwiedziny naszej aplikacji kontrolowane przez skrypt service worker wczytują się nieco szybciej niż odwiedziny niekontrolowane, nawet w przypadku powracających użytkowników, którzy prawdopodobnie mieli w pamięci podręcznej większość zasobów strony. Warto też zauważyć, że użytkownicy urządzeń mobilnych z skryptami service worker wczytują się średnio szybciej niż nowi użytkownicy korzystający z komputerów.

„...wizyty w aplikacji kontrolowane przez skrypt service worker wczytują się znacznie szybciej niż wizyty niekontrolowane...”

Więcej informacji znajdziesz w tych 2 tabelach:

Śr. czas wczytywania strony (komputer)
Stan skryptu service worker Typ użytkownika Śr. czas wczytywania strony (ms) Rozmiar próbki
Sterowano Powracający użytkownik 2568 30860
Obsługiwane Powracający użytkownik 3612 1289
Obsługiwane Nowy użytkownik 4664 21991
Śr. czas wczytywania strony (urządzenia mobilne)
Stan skryptu service worker Typ użytkownika Śr. czas wczytywania strony (ms) Rozmiar próbki
Sterowano Powracający użytkownik 3760 8162
Obsługiwane Powracający użytkownik 4843 676
Obsługiwane Nowy użytkownik 6158 5779

Być może zastanawiasz się, w jaki sposób powracający użytkownik, którego przeglądarka obsługuje mechanizm Service Worker, może znaleźć się w stanie niekontrolowanym. Istnieje kilka możliwych przyczyn tej sytuacji:

  • Użytkownik opuścił stronę podczas pierwszej wizyty, zanim skrypt service worker miał możliwość zakończenia inicjowania.
  • Użytkownik odinstalował skrypt service worker za pomocą narzędzi dla programistów.

Obie te sytuacje występują stosunkowo rzadko. Widać to w danych, patrząc na wartości Próbka wczytywania strony w czwartej kolumnie. Zwróć uwagę, że środkowe wiersze mają znacznie mniejszą próbkę niż pozostałe.

Drugie pytanie brzmiało: Jak skrypt service worker wpływa na wczytywanie witryny?

Aby odpowiedzieć na to pytanie, utworzyliśmy kolejny raport niestandardowy dotyczący danych Śr. wartość zdarzenia i przefiltrowaliśmy wyniki, tak aby uwzględniały tylko zdarzenia firstpaint. Użyliśmy wymiaru Kategoria urządzenia i naszego niestandardowego wymiaru Stan skryptu service worker.

Wbrew oczekiwaniom, mechanizm service worker na urządzeniu mobilnym miał znacznie mniejszy wpływ na czas pierwszego wyrenderowania niż na ogólne wczytanie strony.

„Skrypt service worker na urządzeniu mobilnym miał znacznie mniejszy wpływ na czas pierwszego wyrenderowania niż na ogólne wczytanie strony”.

Aby ustalić, dlaczego tak się dzieje, musimy bardziej szczegółowo przeanalizować dane. Średnie mogą być przydatne w przypadku ogólnych streszczeń i ogólnych kresek, ale aby naprawdę zrozumieć, jak te dane rozkładają się na różnych użytkowników, musimy sprawdzić rozkład firstpaint razy.

Jak uzyskać rozkład danych w Google Analytics

Aby uzyskać rozkład firstpaint razy, potrzebujemy dostępu do poszczególnych wyników z każdego wydarzenia. Google Analytics nie ułatwia jednak tego zadania.

Google Analytics umożliwia podział raportu według dowolnych wymiarów, ale nie umożliwia podziału raportu według danych. Nie oznacza to jednak, że jest to niemożliwe. Oznacza to, że aby uzyskać oczekiwany rezultat, musieliśmy bardziej dostosować naszą implementację.

Wyniki raportu można podzielić tylko według wymiarów, więc musieliśmy ustawić wartość danych (w tym przypadku firstpaint raz) jako wymiar niestandardowy dla zdarzenia. W tym celu utworzyliśmy kolejny wymiar niestandardowy o nazwie Wartość danych i zaktualizowaliśmy mechanizmy śledzenia firstpaint w taki sposób:

var customDimensions = {
  SERVICE_WORKER_STATUS: 'dimension1',
  <strong>METRIC_VALUE: 'dimension2'</strong>
};

// ...

function sendTimeToFirstPaint() {
  var timeToFirstPaint = getTimeToFirstPaintIfSupported();

  if (timeToFirstPaint) {
    var fields = {
      eventCategory: 'Performance',
      eventAction: 'firstpaint',
      // Rounds to the nearest millisecond since
      // event values in Google Analytics must be integers.
      eventValue: Math.round(timeToFirstPaint)
      // Sends this as a non-interaction event,
      // so it doesn't affect bounce rate.
      nonInteraction: true
    }

    <strong>// Sets the event value as a dimension to allow for breaking down the
    // results by individual metric values at reporting time.
    fields[customDimensions.METRIC_VALUE] = String(fields.eventValue);</strong>

    ga('send', 'event', fields);
  }
}

Interfejs internetowy Google Analytics obecnie nie umożliwia wizualizacji rozkładu wartości dowolnych danych, ale dzięki interfejsowi API podstawowego raportowania Google Analytics i bibliotece wykresów Google mogliśmy przesłać zapytanie o nieprzetworzone wyniki i samodzielnie wygenerować histogram.

Na przykład ta konfiguracja żądania do interfejsu API została użyta do uzyskania dystrybucji wartości firstpaint na komputerze za pomocą niekontrolowanego skryptu service worker.

{
  dateRanges: [{startDate: '2016-05-16', endDate: '2016-05-22'}],
  metrics: [{expression: 'ga:totalEvents'}],
  dimensions: [{name: 'ga:dimension2'}],
  dimensionFilterClauses: [
    {
      operator: 'AND',
      filters: [
        {
          dimensionName: 'ga:eventAction',
          operator: 'EXACT',
          expressions: ['firstpaint']
        },
        {
          dimensionName: 'ga:dimension1',
          operator: 'EXACT',
          expressions: ['supported']
        },
        {
          dimensionName: 'ga:deviceCategory',
          operator: 'EXACT',
          expressions: ['desktop']
        }
      ],
    }
  ],
  orderBys: [
    {
      fieldName: 'ga:dimension2',
      orderType: 'DIMENSION_AS_INTEGER'
    }
  ]
}

To żądanie do interfejsu API zwraca tablicę wartości, które wyglądają tak (uwaga: to tylko pięć pierwszych wyników). Wyniki są sortowane od najmniejszej do największej, więc te wiersze odpowiadają najszybszemu czasowi.

Wyniki odpowiedzi interfejsu API (pierwsze 5 wierszy)
ga:wymiar2 ga:totalEvents
4 3
5 2
6 10
7 8
8 10

Znaczenie tych wyników jest proste w języku angielskim:

  • Wystąpiły 3 zdarzenia, przy których wartość firstpaint wynosiła 4 ms
  • Wystąpiły 2 zdarzenia, w których wartość firstpaint wynosiła 5 ms
  • Wystąpiło 10 zdarzeń, w przypadku których wartość firstpaint wynosiła 6 ms
  • Wystąpiło 8 zdarzeń, przy których wartość firstpaint wynosiła 7 ms
  • Wystąpiło 10 zdarzeń, przy których wartość firstpaint value trwała 8 ms.
  • itd.

Na podstawie tych wyników możemy ekstrapolować wartość firstpaint dla każdego zdarzenia i utworzyć histogram rozkładu. Tak samo postąpiliśmy w przypadku każdego uruchamianego zapytania.

Dystrybucja na komputerach z użyciem niekontrolowanego (ale obsługiwanego) skryptu service worker wygląda tak:

Czas do pierwszego wyrenderowania wersji na komputerze (obsługiwany)

Mediana czasu firstpaint dla powyższego rozkładu wynosi 912 ms.

Kształt tej krzywej jest dość typowy dla rozkładu czasu wczytywania. Jest on natomiast widoczny na histogramie poniżej, który przedstawia rozkład zdarzeń pierwszego wyrenderowania w przypadku wizyt, podczas których skrypt service worker kontrolował stronę.

Czas do pierwszego wyrenderowania dystrybucji na komputerze (kontrolowany)

Zwróć uwagę, że gdy skrypt service worker sterował stroną, u wielu użytkowników doszło do pierwszego wyrenderowania, które wystąpiło niemal natychmiast, a mediana wynosiła 583 ms.

„...gdy pracownik Service Worker kontrolował stronę, wielu użytkowników bezpośrednio zobaczyło pierwsze wyrenderowanie strony...”

Aby lepiej porównać ze sobą te 2 rozkłady, następny wykres przedstawia ich widok scalony. Histogram pokazujący niekontrolowane wizyty instancji roboczych jest nałożony na histogram przedstawiający kontrolowane wizyty. Oba są nałożone na histogram pokazujący ich połączenie.

Czas pierwszego renderowania dystrybucji na komputerze

Ciekawe w tych wynikach było to, że po początkowym wzroście liczby wyświetleń rozkład z kontrolowanym mechanizmem Service Worker nadal miał krzywą dzwonową. Spodziewałem się dużego, początkowego wzrostu, a potem stopniowego spadku krzywej. Nie spodziewałem się drugiego szczytu.

Po sprawdzeniu, co może powodować problem, okazało się, że chociaż skrypt service worker kontroluje stronę, jej wątek może być nieaktywny. Przeglądarka robi to, aby zaoszczędzić zasoby. Oczywiście nie każdy skrypt service worker dla każdej odwiedzanej witryny jest aktywny i gotowy w każdej chwili. To wyjaśnia fabułę rozkładu. W przypadku niektórych użytkowników wystąpiło opóźnienie podczas uruchamiania wątku skryptu service worker.

Jak widać jednak podczas dystrybucji, nawet przy takim początkowym opóźnieniu przeglądarki z mechanizmem Service Worker dostarczają treści szybciej niż przeglądarki przechodzące przez sieć.

Tak wyglądało na komórce:

Czas pierwszego renderowania dystrybucji na urządzeniach mobilnych

Chociaż w dalszym ciągu obserwowaliśmy znaczny wzrost liczby pierwszego wyrenderowania, ogon był trochę większy i dłuższy. Jest to prawdopodobnie spowodowane tym, że uruchomienie nieaktywnego wątku skryptu service worker na urządzeniu mobilnym trwa dłużej niż na komputerze. Wyjaśnia też, dlaczego różnica między średnim czasem w usłudze firstpaint nie była tak duża, jak się spodziewałem (omówiono powyżej).

„...uruchomienie nieaktywnego wątku skryptu service worker na urządzeniu mobilnym trwa dłużej niż na komputerze”.

Oto zestawienie tych wariantów mediany czasu pierwszego wyrenderowania na urządzeniach mobilnych i komputerach, pogrupowanych według stanu skryptu service worker:

Mediana czasu do pierwszego wyrenderowania (ms)
Stan skryptu service worker Komputer Urządzenia mobilne
Sterowano 583 1634
Obsługiwane (niekontrolowane) 912 1933

Chociaż tworzenie tych wizualizacji rozkładu pochłaniało trochę więcej czasu i wysiłku niż tworzenie niestandardowego raportu w Google Analytics, dają nam znacznie lepsze pojęcie o tym, jak mechanizmy Service Worker wpływają na wydajność naszej witryny, niż tylko uśrednione.

Inny wpływ skryptów service worker

Mechanizmy Service Worker wpływają nie tylko na wydajność, ale także na wrażenia użytkowników na kilka innych sposobów, które można zmierzyć w Google Analytics.

Dostęp offline

Mechanizmy Service Worker pozwalają użytkownikom na interakcję z witryną w trybie offline, a chociaż jakaś obsługa w trybie offline jest prawdopodobnie niezbędna dla każdej progresywnej aplikacji internetowej, jej znaczenie w Twoim przypadku w dużym stopniu zależy od intensywności użytkowania w trybie offline. Ale jak to mierzymy?

Wysyłanie danych do Google Analytics wymaga połączenia z internetem, ale nie wymaga przesłania danych dokładnie w momencie interakcji. Google Analytics obsługuje wysyłanie danych interakcji po fakcie przez określenie przesunięcia czasu (za pomocą parametru qt).

Od 2 lat IOWA korzysta ze skryptu service worker, który wykrywa w Google Analytics nieudane działania, gdy użytkownik jest offline, i później odtwarza je z parametrem qt.

Aby śledzić, czy użytkownik był online, czy offline, utworzyliśmy wymiar niestandardowy Online i ustawiliśmy dla niego wartość navigator.onLine, potem odsłuchaliśmy zdarzenia online i offline i odpowiednio zaktualizowaliśmy wymiar.

Aby przekonać się, jak powszechna jest sytuacja, w której użytkownicy są offline podczas korzystania z IOWA, utworzyliśmy segment, który kierował reklamy na użytkowników z co najmniej 1 interakcją offline. Okazało się, że było to prawie 5% użytkowników.

Powiadomienia push

Skrypty service worker pozwalają użytkownikom wyrazić zgodę na otrzymywanie powiadomień push. W organizacji IOWA użytkownicy byli informowani o zbliżającej się rozpoczęciu sesji w ich harmonogramie.

Tak jak w przypadku każdej formy powiadomień, ważne jest, aby znaleźć równowagę między dostarczaniem użytkownikowi wartości a ich irytowaniem. Aby lepiej zrozumieć, co się dzieje, warto śledzić, czy użytkownicy wyrażają zgodę na otrzymywanie takich powiadomień, czy wchodzą z nimi w interakcję, gdy już do nich dotrą, oraz czy użytkownicy, którzy wcześniej wyrazili zgodę, zmienili swoje preferencje i zrezygnowali z ich otrzymywania.

W IOWA wysyłaliśmy tylko powiadomienia dotyczące spersonalizowanego harmonogramu użytkownika, czyli coś, co mogą tworzyć tylko zalogowani użytkownicy. Ograniczyło to grupę użytkowników, którzy mogli otrzymywać powiadomienia do zalogowanych użytkowników (śledzonych za pomocą wymiaru niestandardowego Zalogowani), których przeglądarki obsługiwały powiadomienia push (śledzone za pomocą innego niestandardowego wymiaru o nazwie Uprawnienia dotyczące powiadomień).

Ten raport został wygenerowany na podstawie danych Użytkownicy i naszego wymiaru niestandardowego „Zgoda na wyświetlanie powiadomień”. Są one podzielone na segmenty według użytkowników, którzy zalogowali się w jakimś momencie, których przeglądarki obsługują powiadomienia push.

Cieszymy się, że ponad połowa naszych zalogowanych użytkowników zdecydowała się otrzymywać powiadomienia push.

Banery promujące instalacje aplikacji

Jeśli aplikacja internetowa z postępami spełnia kryteria i często jest używana przez użytkownika, może zobaczyć baner instalacji aplikacji z prośbą o dodanie aplikacji do ekranu głównego.

W programie IOWA śledziliśmy, jak często te prośby były wyświetlane użytkownikowi (i czy zostały zaakceptowane) przy użyciu tego kodu:

window.addEventListener('beforeinstallprompt', function(event) {
  // Tracks that the user saw a prompt.
  ga('send', 'event', {
    eventCategory: 'installprompt',
    eventAction: 'fired'
  });

  event.userChoice.then(function(choiceResult) {
    // Tracks the users choice.
    ga('send', 'event', {
      eventCategory: 'installprompt',
      // `choiceResult.outcome` will be 'accepted' or 'dismissed'.
      eventAction: choiceResult.outcome,
      // `choiceResult.platform` will be 'web' or 'android' if the prompt was
      // accepted, or '' if the prompt was dismissed.
      eventLabel: choiceResult.platform
    });
  });
});

Około 10% użytkowników, którzy zobaczyli baner promujący instalację aplikacji, zdecydowało się dodać go do ekranu głównego.

Możliwe ulepszenia śledzenia (przy następnym razem)

Dane analityczne, które zebraliśmy w tym roku w ramach inicjatywy IOWA, były bezcenne. Ale spojrzenie zawsze niesie ze sobą światła i szanse na ulepszenia, które mogą nam pomóc następnym razem. Po zakończeniu tegorocznej analizy oto 2 rzeczy, które chciałabym uwzględnić inaczej, niż czytelnicy, którzy chcą wdrożyć podobną strategię:

1. Śledź więcej zdarzeń związanych z wczytywaniem treści

Śledziliśmy kilka zdarzeń powiązanych z danymi technicznymi (np. HTMLImportsLoaded, WebComponentsReady itp.), ale ze względu na to, że tak duża część obciążenia była realizowana asynchronicznie, moment uruchomienia tych zdarzeń niekoniecznie odpowiadał konkretnemu momentowi na ogólnym procesie ładowania.

Główne zdarzenie związane z wczytywaniem, którego nie śledziliśmy (choć wolelibyśmy, żebyśmy tego nie robili), to moment, w którym ekran powitalny znika, a użytkownik może zobaczyć zawartość strony.

2. zapisz identyfikator klienta Analytics w IndexedDB

Domyślnie kod analytics.js przechowuje pole identyfikatora klienta w plikach cookie przeglądarki. Niestety skrypty service worker nie mają dostępu do plików cookie.

Stanowiło to problem, gdy próbowaliśmy wdrożyć śledzenie powiadomień. Chcieliśmy wysyłać zdarzenie za każdym razem, gdy skrypt service worker zostanie wysłane do użytkownika (za pomocą Measurement Protocol), a następnie śledzić skuteczność ponownego zaangażowania, gdy użytkownik kliknął reklamę i wrócił do aplikacji.

Mogliśmy śledzić ogólną skuteczność powiadomień za pomocą parametru kampanii utm_source, ale nie byliśmy w stanie powiązać konkretnej sesji ponownego zaangażowania z konkretnym użytkownikiem.

Aby obejść to ograniczenie, mogliśmy zapisać identyfikator klienta za pomocą IndexedDB w naszym kodzie śledzenia, a następnie wartość ta była dostępna dla skryptu skryptu service worker.

3. Zezwól mechanizmowi Service Worker na raportowanie stanu online/offline

Sprawdzenie navigator.onLine pokaże, czy przeglądarka może połączyć się z routerem lub siecią lokalną, ale niekoniecznie pokaże, czy użytkownik ma rzeczywiste połączenie. A ponieważ w skrypcie skryptu skryptu service worker offline udało się po prostu odtworzyć nieudane działania (bez ich modyfikowania czy oznaczania jako nieudane), prawdopodobnie niedostatecznie uwzględnialiśmy w raportach użycie w trybie offline.

W przyszłości powinniśmy śledzić zarówno stan działania navigator.onLine, jak i to, czy działanie zostało ponownie odtworzone przez mechanizm Service Worker w wyniku początkowej awarii sieci. Dzięki temu uzyskamy dokładniejszy obraz rzeczywistego użytkowania offline.

Podsumowanie

To studium przypadku wykazało, że zastosowanie mechanizmów service worker faktycznie zwiększyło wydajność wczytywania aplikacji internetowej Google I/O w szerokiej gamie przeglądarek, sieci i urządzeń. Wykazała również, że analizując rozkład danych wczytywania w szerokiej gamie przeglądarek, sieci i urządzeń, można uzyskać znacznie lepszy wgląd w to, jak ta technologia radzi sobie w rzeczywistych scenariuszach, oraz odkryć nieoczekiwane dane o wydajności.

Oto kilka najważniejszych wniosków z badania IOWA:

  • Przeciętnie strony wczytywały się nieco szybciej, gdy skrypt service worker kontrolował stronę, niż bez tego mechanizmu, zarówno w przypadku nowych, jak i powracających użytkowników.
  • Wizyty na stronach kontrolowanych przez skrypt service worker są wczytywane niemal natychmiast u wielu użytkowników.
  • Uruchamianie mechanizmów Service Worker w czasie braku aktywności trwało trochę. Jednak nieaktywne mechanizmy Service Worker nadal miały lepsze wyniki niż żaden inny skrypt service worker.
  • Czas uruchomienia nieaktywnego skryptu service worker był dłuższy na urządzeniu mobilnym niż na komputerze.

Mimo że wzrost wydajności zaobserwowany w jednej aplikacji jest zwykle przydatny w informacjach o szerszej społeczności programistów, należy pamiętać, że wyniki dotyczą konkretnego typu witryny IOWA (witryna z wydarzeniem) i typu odbiorców IOWA (głównie programistów).

Jeśli wdrażasz mechanizm service worker w swojej aplikacji, musisz wdrożyć własną strategię pomiarową, by móc ocenić własną skuteczność i zapobiec regresjom w przyszłości. Jeśli tak, podziel się wynikami, aby wszyscy mogli skorzystać z tej funkcji.

Przypisy

  1. Porównanie wydajności naszej pamięci podręcznej skryptu service worker z wydajnością witryny korzystającej tylko z pamięci podręcznej HTTP nie jest całkowicie uczciwe. Ponieważ optymalizowaliśmy IOWA pod kątem skryptu service worker, nie poświęcaliśmy dużo czasu na optymalizację pod kątem pamięci podręcznej HTTP. Gdyby tak się stało, wyniki prawdopodobnie byłyby inne. Więcej informacji o optymalizacji witryny pod kątem pamięci podręcznej HTTP znajdziesz w artykule Optymalizowanie treści.
  2. W zależności od sposobu wczytywania stylów i treści witryna może być w stanie malować elementy przed udostępnieniem treści lub stylów. W takich przypadkach firstpaint może odpowiadać pustemu białym ekranie. Jeśli używasz atrybutu firstpaint, musisz upewnić się, że odpowiada on konkretnemu momentowi wczytywania zasobów witryny.
  3. Technicznie rzecz biorąc, możemy wysłać działanie czasowe (domyślnie niewymagające interakcji), aby zarejestrować te informacje, a nie zdarzenie. Działania związane z czasem zostały dodane do Google Analytics w celu śledzenia takich danych obciążenia. Działania związane z czasem są jednak w trakcie przetwarzania dużo próbkowane i ich wartości nie można używać w segmentach. Biorąc pod uwagę te obecne ograniczenia, lepiej nadają się do tego zdarzenia niezwiązane z interakcjami.
  4. Aby dowiedzieć się, jaki zakres przypisać do niestandardowego wymiaru w Google Analytics, zajrzyj do sekcji Wymiar niestandardowy w Centrum pomocy Analytics. Ważne jest również poznanie modelu danych Google Analytics, który składa się z użytkowników, sesji i interakcji (działań). Więcej informacji znajdziesz w lekcji Akademii Analytics o modelu danych Google Analytics.
  5. Nie uwzględnia to zasobów leniwie ładowanych po zdarzeniu wczytywania.