Jednym z największych zalet usług działających w tle (przynajmniej pod względem wydajności) jest możliwość aktywnego kontrolowania buforowania zasobów. Aplikacja internetowa, która może buforować wszystkie potrzebne zasoby, powinna ładować się znacznie szybciej u powracających użytkowników. Jak jednak te korzyści wyglądają w przypadku prawdziwych użytkowników? Jak to mierzyć?
Aplikacja internetowa Google I/O to progresywna aplikacja internetowa, która wykorzystała większość nowych funkcji oferowanych przez pracowników usługowych, aby zapewniać użytkownikom zaawansowane funkcje przypominające aplikacje. Firma korzystała też z Google Analytics, aby rejestrować kluczowe dane o skuteczności i wzorcach korzystania z usługi przez dużą i zróżnicowaną grupę odbiorców.
To studium przypadku pokazuje, w jaki sposób firma IOWA wykorzystała Google Analytics do uzyskania odpowiedzi na kluczowe pytania dotyczące wydajności i stworzenia raportów dotyczących rzeczywistego wpływu pracowników Service Worker.
Zacznij od pytania
Za każdym razem, gdy wdrażasz analitykę w witrynie lub aplikacji, ważne jest, aby zacząć od identyfikacji pytań, na które starasz się odpowiedzieć na podstawie danych, które będziesz zbierać.
W ramach tego opracowania skupimy się na 2 najbardziej interesujących pytaniach, choć mieliśmy ich znacznie więcej.
1. Czy pamięć podręczna skryptu service worker jest bardziej wydajna niż istniejące mechanizmy buforowania HTTP dostępne we wszystkich przeglądarkach?
Oczekujemy, że strony wczytują się szybciej w przypadku powracających użytkowników niż nowych, ponieważ przeglądarki mogą przechowywać żądania w pamięci podręcznej i odtwarzać je natychmiast podczas kolejnych wizyt.
Skrypty service worker udostępniają alternatywne funkcje buforowania, które dają programistom szczegółową kontrolę nad tym, co i w jaki sposób odbywa się w pamięci podręcznej. W przypadku IOWA zoptymalizowaliśmy implementację usług workera, aby każdy zasób był przechowywany w pamięci podręcznej, dzięki czemu powracający użytkownicy mogli korzystać z aplikacji całkowicie offline.
Czy jednak jest to lepsze rozwiązanie niż to, co przeglądarka robi domyślnie? Jeśli tak, o ile? 1
2. Jak skrypt service worker wpływa na wczytywanie strony?
Innymi słowy, jak szybko wydaje się, że strona się wczytuje, niezależnie od rzeczywistego czasu wczytywania mierzonego za pomocą tradycyjnych danych o wczytywaniu strony?
Odpowiedź na pytania o odczucia nie jest łatwym zadaniem, a żadne dane nie oddadzą w pełni subiektywnego odczucia. Zdecydowanie jednak niektóre dane są lepsze od innych, dlatego warto wybrać te właściwe.
Wybór odpowiednich danych
Domyślnie Google Analytics śledzi czas wczytywania stron (za pomocą interfejsu Navigation Timing API) w przypadku 1% użytkowników witryny i udostępnia te dane w postaci danych takich jak Średni czas wczytywania strony.
Średni czas wczytywania strony to dobry wskaźnik do udzielenia odpowiedzi na pierwsze pytanie, ale nie jest on szczególnie przydatny do udzielenia odpowiedzi na drugie. Po pierwsze, zdarzenie load
niekoniecznie odpowiada momentowi, w którym użytkownik może wchodzić w interakcję z aplikacją. Co więcej, 2 aplikacje z identycznym czasem wczytywania mogą wydawać się wczytywane znacznie szybciej lub wolniej. Na przykład witryna z ekranem powitalnym lub wskaźnikiem wczytywania prawdopodobnie wczytuje się znacznie szybciej niż witryna, która przez kilka sekund wyświetla tylko pustą stronę.
W IOWA wyświetlaliśmy animację odliczania na ekranie powitalnym, która (według nas) bardzo skutecznie zajmowała użytkowników, gdy reszta aplikacji wczytywała się w tle. Z tego powodu śledzenie czasu potrzebnego na pojawienie się ekranu powitalnego ma więcej sensu. Aby uzyskać tę wartość, wybraliśmy dane Czas do pierwszego wyświetlenia.
Gdy określiliśmy pytania, na które chcemy uzyskać odpowiedzi, i wyznaczyliśmy dane, które pomogą nam je rozwikłać, nadszedł czas na wdrożenie Google Analytics i rozpoczęcie pomiarów.
Implementacja analityki
Jeśli korzystasz już z Google Analytics, prawdopodobnie 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 w powyższym kodzie inicjalizuje globalną funkcję ga()
(jeśli jeszcze nie istnieje), a ostatni wiersz asynchronicznie pobiera bibliotekę analytics.js
.
Środkowa część zawiera następujące dwa wiersze:
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 przypadku IOWA chcieliśmy śledzić 2 dodatkowe kwestie:
- Czas od rozpoczęcia wczytywania strony do pojawienia się pikseli na ekranie.
- Określa, czy stroną steruje skrypt service worker. Dysponując tymi informacjami, możemy posegmentować raporty, aby porównać wyniki z użyciem skryptu service worker i bez niego.
Rejestrowanie czasu do pierwszego wyrenderowania
Niektóre przeglądarki rejestrują dokładny czas, w którym pierwszy piksel jest wyświetlany na ekranie, i udostępniają go deweloperom. Porównanie tej wartości z wartością navigationStart
podaną przez interfejs API Czas nawigacji pozwala nam bardzo dokładnie określić, ile czasu upłynęło od momentu, gdy użytkownik wysłał pierwsze żądanie strony, do momentu, gdy po raz pierwszy zobaczył coś na stronie.
Jak już wspomniałem, czas do pierwszego wyświetlenia jest ważnym wskaźnikiem, ponieważ to pierwszy moment, w którym użytkownik odczuwa szybkość wczytywania witryny. To pierwsze wrażenie, jakie użytkownicy odnoszą. Dobre pierwsze wrażenie może pozytywnie wpłynąć na pozostałe wrażenia użytkownika2
Aby uzyskać wartość pierwszej aktualizacji w przeglądarkach, które ją udostępniają, utworzyliśmy funkcję użyteczności 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;
}
}
}
Teraz możemy napisać inną funkcję, która wysyła zdarzenie niezwiązane z interakcją z wartością odpowiadającą czasowi pierwszego wyświetlenia: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żej działa kod, piksele mogły zostać wcześniej wyrenderowane na ekranie. Aby mieć pewność, że ten kod jest zawsze wykonywany po pierwszym wyświetleniu, opóźniliśmy wywołanie funkcji sendTimeToFirstPaint()
do momentu wystąpienia zdarzenia load
. Zdecydowaliśmy się o opóźnieniu wysyłania wszystkich danych analitycznych do momentu wczytania strony, aby te żądania nie kolidowały 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();
});
Kod powyżej raportuje do Google Analytics liczbę wystąpień firstpaint
, ale to tylko połowa historii. Nadal musieliśmy śledzić stan skryptu service worker. W przeciwnym razie nie bylibyśmy w stanie porównać pierwszych czasów renderowania strony kontrolowanej przez ten mechanizm i strony niekontrolowanej.
Określanie stanu skryptu service worker
Aby określić bieżący stan usługi, utworzyliśmy funkcję pomocniczą, która zwraca jedną z 3 wartości:
- sterowana: stroną steruje skrypt service worker. W przypadku IOWA oznacza to również, że wszystkie zasoby zostały zapisane w pamięci podręcznej, a strona działa offline.
- obsługiwany: przeglądarka obsługuje skrypt service worker, ale nie steruje jeszcze stroną. To oczekiwany stan dla nowych użytkowników.
- Nieobsługiwane: przeglądarka użytkownika nie obsługuje usługi workera.
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. Następnym krokiem było powiązanie tego stanu z danymi, które wysłaliśmy do Google Analytics.
Śledzenie danych niestandardowych za pomocą wymiarów niestandardowych
Domyślnie Google Analytics udostępnia wiele sposobów podziału całkowitego ruchu na grupy na podstawie atrybutów użytkownika, sesji lub interakcji. Te atrybuty nazywamy wymiarami. Typowe wymiary, na których zależy deweloperom stron internetowych, to Przeglądarka, System operacyjny i Kategoria urządzenia.
Stan usługi to nie wymiar domyślnie udostępniany przez Google Analytics, ale możesz utworzyć własne wymiary niestandardowe i zdefiniować je według własnego uznania.
W przypadku IOWA utworzyliśmy wymiar niestandardowy o nazwie Service Worker Status i ustawiliśmy jego zakres na hit (czyli na interakcję).4 Każdy wymiar niestandardowy utworzony w Google Analytics otrzymuje w tej usłudze swój niepowtarzalny indeks, a w kodzie śledzenia możesz się do niego odwoływać za pomocą tego indeksu. Jeśli np. indeks utworzonego przez nas wymiaru wynosi 1, możemy zaktualizować logikę w ten sposób, aby wysyłać zdarzenie firstpaint
z uwzględnieniem stanu workera usługi:
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 tylko wiąże stan usługi z tym konkretnym zdarzeniem. Stan Service Worker może być przydatny w przypadku każdej interakcji, dlatego najlepiej uwzględniać go we wszystkich danych wysyłanych do Google Analytics.
Aby uwzględnić te informacje we wszystkich uchwytach (np. we wszystkich wyświetleniach stron, zdarzeniach itp.), ustawiamy wartość wymiaru niestandardowego w samym obiekcie tracker, zanim jakiekolwiek dane zostaną wysłane do Google Analytics.
ga('set', 'dimension1', getServiceWorkerStatus());
Gdy zostanie ustawiona, jest wysyłana ze wszystkimi kolejnymi uchwytami bieżącego wczytania strony. Jeśli użytkownik ponownie załaduje stronę, z funkcji getServiceWorkerStatus()
prawdopodobnie zostanie zwrócona nowa wartość, która zostanie ustawiona w obiekcie śledzenia.
Wskazówka dotycząca przejrzystości i czytelności kodu: inne osoby, które będą przeglądać ten kod, mogą nie wiedzieć, co oznacza dimension1
, dlatego zawsze warto utworzyć zmienną, która mapuje znaczące nazwy wymiarów na wartości używane przez 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ż wspominaliśmy, wysłanie wymiaru Stan skryptu Service Worker z każdym działaniem umożliwia nam korzystanie z niego w raportach o dowolnych danych.
Jak widać, prawie 85% wszystkich wyświetleń strony w przypadku IOWA pochodziło z przeglądarek, które obsługują skrypt service worker.
Odpowiedzi na pytania
Gdy zaczęliśmy zbierać dane, aby uzyskać odpowiedzi na nasze pytania, mogliśmy tworzyć raporty na ich podstawie. (Uwaga: wszystkie dane Google Analytics przedstawione tutaj odzwierciedlają rzeczywisty ruch w witrynie IOWA w dniach 16–22 maja 2016 r.)
Pierwsze pytanie, jakie sobie zadaliśmy, brzmiało: Czy buforowanie w ramach usługi workera jest wydajniejsze niż istniejące mechanizmy buforowania HTTP dostępne we wszystkich przeglądarkach?
Aby uzyskać odpowiedź na to pytanie, utworzyliśmy raport niestandardowy, w którym uwzględniliśmy dane Średni czas wczytywania strony w różnych wymiarach. Te dane dobrze nadają się do uzyskania odpowiedzi na to pytanie, ponieważ zdarzenie load
jest uruchamiane dopiero po pobraniu wszystkich zasobów początkowych. Odzwierciedla więc bezpośrednio łączny czas wczytywania wszystkich kluczowych zasobów witryny5.
Wybrane przez nas wymiary to:
- Nasz niestandardowy wymiar Stan skryptu Service Worker.
- Typ użytkownika, który wskazuje, czy jest to pierwsza wizyta użytkownika w witrynie, czy powraca on do niej. (Uwaga: nowy użytkownik nie będzie miał żadnych zasobów w pamięci podręcznej, ale powracający użytkownik może mieć).
- Kategoria urządzenia, która umożliwia porównanie wyników na urządzeniach mobilnych i komputerach.
Aby wykluczyć możliwość, że wyniki dotyczące czasu wczytywania są zafałszowane przez czynniki inne niż związane ze skryptem usługi, ograniczyliśmy nasze zapytanie do przeglądarek obsługujących skrypt usługi.
Jak widać, wizyty w naszej aplikacji, gdy były kontrolowane przez skrypt service worker, wczytywały się znacznie szybciej niż wizyty bez kontroli, nawet te od powracających użytkowników, którzy prawdopodobnie mieli większość zasobów strony w pamięci podręcznej. Warto też zauważyć, że w przypadku użytkowników mobilnych z usługą workera usług nawigacji wczytywanie było średnio szybsze niż w przypadku nowych użytkowników na komputerach.
„...wizyty w naszej aplikacji kontrolowane przez skrypt service worker ładowały się znacznie szybciej niż wizyty niekontrolowane...”
Więcej informacji znajdziesz w tych 2 tabelach:
Śr. czas wczytywania strony (komputera) | |||
---|---|---|---|
Stan skryptu Service Worker | Typ użytkownika | Śr. czas wczytywania strony (ms) | Wielkość 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) | Wielkość 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 znajdować się w niekontrolowanym stanie. Możliwych jest kilka przyczyn tej sytuacji:
- Użytkownik opuścił stronę podczas pierwszej wizyty, zanim skrypt service worker zdążył się zainicjować.
- Użytkownik odinstalował service workera za pomocą narzędzi dla deweloperów.
Obie te sytuacje są stosunkowo rzadkie. Widać to w danych w kolumnie Próbka czasu wczytywania strony. Zwróć uwagę, że środkowe wiersze zawierają znacznie mniejszą próbkę niż pozostałe.
Drugie pytanie brzmiało: Jak usługa typu service worker wpływa na wczytywanie witryny?
Aby uzyskać odpowiedź na to pytanie, utworzyliśmy kolejny raport niestandardowy z danymi Śr. wartość zdarzenia i odfiltrowaliśmy wyniki tak, aby uwzględniały tylko zdarzenia firstpaint
. Użyliśmy wymiarów Kategoria urządzenia i naszego wymiaru niestandardowego Stan pracownika usługi.
Wbrew moim oczekiwaniom, usługa wtyczki na urządzeniach mobilnych miała znacznie mniejszy wpływ na czas do pierwszego wyświetlenia niż na ogólne wczytywanie strony.
„...usługodawca na urządzeniach mobilnych miał znacznie mniejszy wpływ na czas pierwszego wyrenderowania niż na ogólne wczytywanie strony”.
Aby to sprawdzić, musimy dokładniej przeanalizować dane. Średnie mogą być przydatne do ogólnego przeglądu i oceny ogólnej sytuacji, ale aby naprawdę zrozumieć, jak te liczby rozkładają się na różnych użytkowników, musimy przyjrzeć się rozkładowi firstpaint
.
Uzyskiwanie rozkładu danych w Google Analytics
Aby uzyskać rozkład wartości firstpaint
, potrzebujemy dostępu do poszczególnych wyników każdego zdarzenia. Google Analytics nie ułatwia tego zadania.
Google Analytics umożliwia podział raportu według dowolnego wymiaru, ale nie według danych. Nie oznacza to, że jest to niemożliwe, ale po prostu musieliśmy jeszcze bardziej dostosować implementację, aby uzyskać pożądany wynik.
Wyniki raportu można rozbicie tylko według wymiarów, więc musieliśmy ustawić wartość danych (w tym przypadku firstpaint
czas) jako wymiar niestandardowy zdarzenia. W tym celu utworzyliśmy kolejny wymiar niestandardowy o nazwie Wartość danych i zmieniliśmy logikę firstpaint
śledzenia w ten 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 nie umożliwia obecnie wizualizacji rozkładu dowolnych wartości danych, ale za pomocą interfejsu Google Analytics Core Reporting API i biblioteki Google Charts mogliśmy wysłać zapytanie o nieprzetworzone wyniki, a potem sami utworzyć histogram.
Aby uzyskać rozkład wartości firstpaint
na komputerach z systemem operacyjnym Windows za pomocą niekontrolowanego service workera, użyliśmy na przykład tej konfiguracji żądania interfejsu API:
{
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 interfejsu API zwraca tablicę wartości wyglądającą tak (uwaga: to tylko 5 pierwszych wyników): Wyniki są sortowane w kolejności od najmniejszej do największej wartości, więc w tych wierszach podane są najszybsze czasy.
Wyniki odpowiedzi interfejsu API (pierwsze 5 wierszy) | |
---|---|
ga:dimension2 | ga:totalEvents |
4 | 3 |
5 | 2 |
6 | 10 |
7 | 8 |
8 | 10 |
Oto co oznaczają te wyniki w prostym języku angielskim:
- W 3 przypadkach 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 których wartość
firstpaint
wynosiła 6 ms - Wystąpiło 8 zdarzeń, w których przypadku wartość
firstpaint
wynosiła 7 ms - Było 10 zdarzeń, w przypadku których czas trwania
firstpaint
value
wynosił 8 ms - itd.
Na podstawie tych wyników możemy ekstrapolować wartość firstpaint
dla każdego zdarzenia i utworzyć histogram rozkładu. Zrobiliśmy to w przypadku każdego z wykonanych zapytań.
Tak wyglądała dystrybucja na komputerach z niekontrolowanym (ale obsługiwanym) skryptem service worker:
Średni czas firstpaint
w przypadku tej dystrybucji to 912 ms.
Kształt tej krzywej jest dość typowy dla rozkładu czasu wczytywania. Porównaj to z histogramem poniżej, który pokazuje rozkład zdarzeń pierwszego wyświetlenia w przypadku wizyt, w których sterowanie stroną przejął pracownik usługi.
Zwróć uwagę, że gdy skrypt service worker kontrolował stronę, wielu użytkowników miało niemal natychmiastowy pierwszy render, a średni czas wynosił 583 ms.
„…gdy skrypt service worker kontrolował stronę, wielu użytkowników miało niemal natychmiastowe wyświetlanie pierwszego rysunku…”
Aby lepiej zrozumieć, jak te 2 rozkłady się od siebie różnią, na następnym wykresie widać je złączone. Histogram pokazujący niekontrolowane wizyty robota usługowego jest nałożony na histogram pokazujący kontrolowane wizyty, a oba są nałożone na histogram pokazujący oba te rodzaje wizyt.
Ciekawym wynikiem było to, że rozkład z kontrolowanym pracownikiem usługi nadal miał krzywą w kształcie dzwonu po początkowym wzroście. Spodziewałem się dużego początkowego skoku, a potem stopniowego wygaszania, ale nie spodziewałem się drugiego szczytu na krzywej.
Gdy zaczęłam szukać przyczyny tego problemu, okazało się, że mimo że skrypt service worker może kontrolować stronę, jego wątek może być nieaktywny. Przeglądarka robi to, aby zaoszczędzić zasoby – oczywiście nie musisz korzystać z każdego skryptu service worker w każdej odwiedzonej witrynie, aby była aktywna i gotowa do działania. To wyjaśnia ogon rozkładu. W przypadku niektórych użytkowników wystąpiło opóźnienie podczas uruchamiania wątku usługi.
Jak widać jednak na podstawie dystrybucji, nawet przy tym początkowym opóźnieniu przeglądarki z skrypcją service worker dostarczały treści szybciej niż te, które korzystają z sieci.
Oto jak to wyglądało na urządzeniu mobilnym:
Wciąż odnotowaliśmy znaczny wzrost czasu pierwszego wyrenderowania treści, ale ogon był nieco dłuższy i szerszy. Prawdopodobnie dlatego, że na urządzeniu mobilnym uruchomienie wątku nieaktywnego service workera zajmuje więcej czasu niż na komputerze. To też wyjaśnia, dlaczego różnica między średnim czasem firstpaint
nie była tak duża, jak się spodziewałem (omówiona powyżej).
„…na urządzeniach mobilnych uruchamianie wątku nieaktywnego service workera trwa dłużej niż na komputerach”.
Oto podział tych wariantów średniego czasu pierwszego wyświetlenia na urządzeniach mobilnych i na komputerach pogrupowanych według stanu usługi:
Mediana czasu do pierwszego wyrenderowania (ms) | ||
---|---|---|
Stan skryptu service worker | Komputer | Urządzenia mobilne |
Sterowano | 583 | 1634 |
Obsługiwane (niekontrolowane) | 912 | 1933 |
Tworzenie tych wizualizacji rozkładu zajęło nam nieco więcej czasu i wysiłku niż tworzenie raportu niestandardowego w Google Analytics, ale dzięki nim znacznie lepiej rozumiemy wpływ usług działających w tle na wydajność naszej witryny niż tylko na podstawie średnich.
Inne skutki skryptów service worker
Oprócz wpływu na wydajność, workery usług wpływają na komfort użytkownika w kilka inne sposoby, które można mierzyć za pomocą Google Analytics.
Dostęp offline
Skrypty service worker umożliwiają użytkownikom interakcję z Twoją witryną w trybie offline. Chociaż w przypadku każdej progresywnej aplikacji internetowej jakikolwiek rodzaj obsługi offline jest prawdopodobnie kluczowy, to określenie, jak bardzo jest on kluczowy w Twoim przypadku, zależy głównie od tego, jak często użytkownicy korzystają z Twojej witryny w trybie offline. Ale jak to zmierzyć?
Przesyłanie danych do Google Analytics wymaga połączenia z internetem, ale nie jest wymagane, aby były wysyłane dokładnie w momencie wystąpienia interakcji. Google Analytics obsługuje wysyłanie danych o interakcji później, określając przesunięcie czasu (za pomocą parametru qt
).
Przez ostatnie 2 lata IOWA używała skryptu usługi, który wykrywa nieudane wywołania Google Analytics, gdy użytkownik jest offline, i odtwarza je później za pomocą parametru qt
.
Aby śledzić, czy użytkownik jest online czy offline, utworzyliśmy wymiar niestandardowy o nazwie Online i ustaliliśmy jego wartość na navigator.onLine
. Następnie nasłuchiwaliśmy zdarzeń online
i offline
, aby odpowiednio zaktualizować wymiar.
Aby dowiedzieć się, jak często użytkownicy korzystają z IOWA offline, utworzyliśmy segment, który obejmował użytkowników z co najmniej jedną interakcją offline. Okazało się, że to prawie 5% użytkowników.
Powiadomienia push
Usługa workera umożliwia użytkownikom zgłaszanie chęci otrzymywania powiadomień push. W IOWA użytkownicy byli powiadamiani, gdy miała się rozpocząć sesja na ich harmonogramie.
Podobnie jak w przypadku innych form powiadomień, ważne jest, aby znaleźć równowagę między dostarczaniem wartości użytkownikowi a drażnieniem go. Aby lepiej zrozumieć, co się dzieje, należy śledzić, czy użytkownicy wyrazili zgodę na otrzymywanie takich powiadomień, czy wchodzą z nimi w interakcję w momencie ich wyświetlenia oraz czy użytkownicy, którzy wcześniej wyrazili zgodę, zmienili swoje preferencje i zrezygnowali z tej funkcji.
W przypadku IOWA wysyłaliśmy tylko powiadomienia związane z spersonalizowanym harmonogramem użytkownika, który mogli tworzyć tylko zalogowani użytkownicy. Ograniczyło to zestaw użytkowników, którzy mogli otrzymywać powiadomienia, do zalogowanych użytkowników (śledzonych za pomocą wymiaru niestandardowego o nazwie Zalogowany), których przeglądarki obsługiwały powiadomienia push (śledzone za pomocą innego wymiaru niestandardowego o nazwie Uprawnienia dotyczące powiadomień).
Ten raport jest oparty na danych Użytkownicy i wymiarze niestandardowym Powiadomienia push, a segmentowany według użytkowników, którzy w danym momencie byli zalogowani, a ich przeglądarki obsługują powiadomienia push.
Cieszymy się, że ponad połowa zalogowanych użytkowników zdecydowała się na otrzymywanie powiadomień push.
Banery promujące instalację aplikacji
Jeśli aplikacja internetowa postępu spełnia kryteria i jest często używana przez użytkownika, może mu się wyświetlić baner promujący instalację aplikacji z prośbą o dodanie jej do ekranu głównego.
W IOWA śledziłyśmy, jak często te prompty były wyświetlane użytkownikom (i czy zostały zaakceptowane) za pomocą 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
});
});
});
Spośród użytkowników, którzy widzieli baner z prośbą o instalację aplikacji, około 10% z nich zdecydowało się dodać ją do ekranu głównego.
Możliwe ulepszenia śledzenia (na przyszłość)
Dane analityczne zebrane przez nas w tym roku w ramach IOWA były bezcenne. Ale wsteczna analiza zawsze pozwala dostrzec luki i możliwości poprawy na przyszłość. Po zakończeniu tegorocznej analizy chciałbym podzielić się 2 rzecząmi, które chcielibyśmy zrobić inaczej. Mogą one być przydatne dla czytelników, którzy chcą wdrożyć podobną strategię:
1. śledzić więcej zdarzeń związanych z obciążeniem,
Śledziłyśmy kilka zdarzeń odpowiadających metrykom technicznym (np. HTMLImportsLoaded, WebComponentsReady itp.), ale ponieważ większość wczytywania była wykonywana asynchronicznie, moment wystąpienia tych zdarzeń niekoniecznie odpowiadał konkretnemu momentowi w całym procesie wczytywania.
Głównym zdarzeniem związanym z wczytywaniem, którego nie śledziliśmy (ale szkoda, że nie mieliśmy), jest moment, w którym ekran powitalny zniknął i użytkownik mógł zobaczyć zawartość strony.
2. Przechowywanie identyfikatora klienta Analytics w IndexedDB
Domyślnie analytics.js przechowuje pole identyfikatora klienta w plikach cookie przeglądarki. Niestety skrypty service worker nie mają dostępu do plików cookie.
Wystąpił z tego powodu problem, gdy próbowaliśmy wdrożyć śledzenie powiadomień. Za każdym razem, gdy wysyłano powiadomienie do użytkownika, chcieliśmy wysłać zdarzenie z serwisowego workera (za pomocą protokołu Measurement Protocol), a potem śledzić skuteczność tego powiadomienia w przypadku ponownego zaangażowania, jeśli użytkownik kliknął powiadomienie i wrócił do aplikacji.
Udało nam się śledzić skuteczność powiadomień w ogóle za pomocą parametru utm_source
campaign, ale nie udało się nam powiązać konkretnej sesji ponownego zaangażowania z konkretnym użytkownikiem.
Mogliśmy obejść to ograniczenie, zapisując identyfikator klienta w IndexedDB w naszym kodzie śledzenia, dzięki czemu wartość ta byłaby dostępna dla skryptu service worker.
3. Zezwalanie skryptu service worker na raportowanie stanu online/offline
Sprawdzenie wartości navigator.onLine
pozwoli Ci się dowiedzieć, czy przeglądarka może połączyć się z routerem lub siecią lokalną, ale niekoniecznie określi, czy użytkownik ma rzeczywiste połączenie. Ponieważ nasz skrypt usługi w ramach usługi offline Analytics po prostu powtarzał nieudane uderzenia (bez ich modyfikowania ani oznaczania jako nieudanych), prawdopodobnie zaniżaliśmy liczbę raportowanych przypadków korzystania z funkcji offline.
W przyszłości powinniśmy śledzić zarówno stan navigator.onLine
, jak i to, czy skrypt service worker odtworzył uderzenie z powodu początkowej awarii sieci. Dzięki temu uzyskamy dokładniejszy obraz rzeczywistego korzystania z aplikacji offline.
Podsumowanie
To studium przypadku pokazuje, że zastosowanie mechanizmu Service Worker rzeczywiście poprawiło wydajność wczytywania aplikacji internetowej Google I/O w wielu przeglądarkach, sieciach i na różnych urządzeniach. Okazało się też, że analiza rozkładu danych o obciążeniu w różnych przeglądarkach, sieciach i na różnych urządzeniach pozwala lepiej zrozumieć, jak ta technologia radzi sobie w rzeczywistych scenariuszach, i odkrywa nieoczekiwane właściwości wydajności.
Oto najważniejsze wnioski z badania IOWA:
- Średnio strony wczytywały się znacznie szybciej, gdy sterował nimi skrypt service worker, niż gdy nie sterował, zarówno w przypadku nowych, jak i powracających użytkowników.
- W przypadku wielu użytkowników wizyty na stronach kontrolowanych przez skrypt service worker wczytują się niemal natychmiast.
- W przypadku nieaktywnych usług roboczych uruchomienie może trochę potrwać. Nieaktywny skrypt service worker działał jednak lepiej niż brak skryptu.
- Czas uruchamiania nieaktywnego skryptu service worker był dłuższy na urządzeniu mobilnym niż na komputerze.
Wzrost wydajności zaobserwowany w konkretnej aplikacji jest zwykle przydatny w raportach szerszej społeczności programistów, ale pamiętaj, że te wyniki zależą od typu witryny IOWA (strona wydarzenia) i jej odbiorców (głównie deweloperów).
Jeśli wdrażasz w aplikacji skrypt service worker, ważne jest, aby zastosować własną strategię pomiarową, która pozwoli Ci ocenić wydajność i zapobiegać przyszłym regresjom. Jeśli tak, udostępnij wyniki, aby wszyscy mogli z nich skorzystać.
Przypisy
- Nie jest do końca sprawiedliwe porównywać wydajność implementacji pamięci podręcznej serwisu workera z wydajnością naszej witryny z samej pamięci podręcznej HTTP. Ponieważ optymalizowaliśmy IOWA pod kątem usługi workera, nie poświęciliśmy zbyt wiele czasu na optymalizację pod kątem pamięci podręcznej HTTP. Gdyby tak było, wyniki pewnie byłyby inne. Więcej informacji o optymalizacji witryny pod kątem pamięci podręcznej HTTP znajdziesz w artykule Efektywne optymalizowanie treści.
- W zależności od tego, jak Twoja witryna wczytuje style i treści, przeglądarka może być w stanie wyświetlić obraz przed udostępnieniem treści lub stylów. W takich przypadkach
firstpaint
może odpowiadać pustemu białemu ekranowi. Jeśli używasz parametrufirstpaint
, musisz się upewnić, że odpowiada on istotnemu punktowi wczytywania zasobów witryny. - Teoretycznie moglibyśmy wysłać metrykę timing (która domyślnie nie jest interakcją), aby zarejestrować te informacje zamiast zdarzenia. Działania czasowe zostały dodane do Google Analytics specjalnie w celu śledzenia danych o obciążeniu w ten sposób. Działania związane z czasem są jednak w trakcie przetwarzania intensywnie próbkowane i ich wartości nie można używać w segmentach. Ze względu na te ograniczenia nadal lepiej sprawdzają się zdarzenia bez interakcji.
- Więcej informacji o zakresie niestandardowego wymiaru w Google Analytics znajdziesz w sekcji Wymiar niestandardowy w Centrum pomocy Analytics. Ważne jest też zrozumienie modelu danych Google Analytics, który składa się z użytkowników, sesji i interakcji (trafień). Aby dowiedzieć się więcej, obejrzyj lekcję Akademii Analytics na temat modelu danych Google Analytics.
- Nie uwzględnia on zasobów wczytywanych z opóźnieniem po zdarzeniu wczytywania.