Einer der bedeutendsten Vorteile von Service Workern (zumindest aus Leistungssicht) besteht darin, dass sie das Caching von Assets proaktiv steuern können. Eine Webanwendung, die alle erforderlichen Ressourcen im Cache speichern kann, sollte für wiederkehrende Besucher wesentlich schneller geladen werden. Aber wie sehen diese Vorteile für echte Nutzende aus? Und wie messen Sie dies überhaupt?
Die Google I/O-Web-App (kurz IOWA) ist eine progressive Web-App, die die meisten der neuen Funktionen von Service Workern nutzt, um ihren Nutzern eine umfassende, App-ähnliche Nutzererfahrung zu bieten. Außerdem nutzte das Unternehmen Google Analytics, um wichtige Leistungsdaten und Nutzungsmuster aus seiner großen und vielfältigen Zielgruppe zu erfassen.
In dieser Fallstudie wird untersucht, wie IOWA mit Google Analytics wichtige Leistungsfragen beantwortet und Berichte über die tatsächlichen Auswirkungen von Service Workern erstellt.
Beginnen wir mit den Fragen
Jedes Mal, wenn Sie Analytics in eine Website oder Anwendung implementieren, ist es wichtig, dass Sie zunächst anhand der zu erfassenden Daten die Fragen identifizieren, die Sie beantworten möchten.
Obwohl wir einige Fragen hatten, die wir beantworten wollten, konzentrieren wir uns für diese Fallstudie auf zwei der interessanteren.
1. Ist das Caching durch den Service Worker leistungsfähiger als die bestehenden HTTP-Caching-Mechanismen, die in allen Browsern verfügbar sind?
Wir erwarten, dass Seiten für wiederkehrende Besucher schneller als für neue Besucher geladen werden, da Browser Anfragen im Cache speichern und bei wiederholten Besuchen sofort ausliefern können.
Service Worker bieten alternative Caching-Funktionen, mit denen Entwickler genau steuern können, was und wie Caching ausgeführt wird. In IOWA haben wir die Service Worker-Implementierung so optimiert, dass jedes Asset im Cache gespeichert wird, sodass wiederkehrende Besucher die App vollständig offline verwenden können.
Wäre dieser Aufwand besser als das, was der Browser bereits standardmäßig tut? Wenn ja, um wie viel besser? 1
2. Wie wirkt sich der Service Worker auf das Laden der Website aus?
Mit anderen Worten: Wie schnell fühlt es sich so an, als ob die Website geladen wird, unabhängig von den tatsächlichen Ladezeiten, die mit den herkömmlichen Messwerten zum Seitenaufbau gemessen werden?
Fragen dazu zu beantworten, wie sich ein Erlebnis anfühlt, ist natürlich nicht leicht, und keine Metrik wird eine solch subjektive Stimmung perfekt repräsentieren. Allerdings gibt es definitiv einige Messwerte, die besser sind als andere. Daher ist es wichtig, die richtigen Messwerte auszuwählen.
Den richtigen Messwert auswählen
Google Analytics erfasst standardmäßig die Seitenladezeiten (über die Navigation Timing API) für 1% der Besucher einer Website und stellt diese Daten über Messwerte wie Durchschn. Seitenladezeit.
Durchschn. Seitenladezeit ist ein guter Messwert für die erste Frage, er ist jedoch kein besonders guter Messwert für die zweite Frage. Zum einen entspricht das load
-Ereignis nicht unbedingt dem Moment, in dem der Nutzer tatsächlich mit der App interagieren kann. Außerdem fühlen sich zwei Apps mit exakt derselben Ladezeit möglicherweise sehr unterschiedlich geladen. Beispielsweise fühlt sich eine Website mit einem Ladebildschirm oder einer Ladeanzeige wahrscheinlich viel schneller geladen als eine Website, auf der nur einige Sekunden lang eine leere Seite angezeigt wird.
In IOWA zeigten wir eine Countdown-Animation für den Ladebildschirm, die (meiner Meinung nach) für den Nutzer sehr gut zur Unterhaltung diente, während der Rest der App im Hintergrund geladen wurde. Aus diesem Grund ist es viel sinnvoller, zu verfolgen, wie lange es dauert, bis der Ladebildschirm erscheint, um die wahrgenommene Lastleistung zu messen. Um diesen Wert zu erhalten, haben wir den Messwert Zeit bis zum ersten Mal ausgewählt.
Nachdem wir uns entschieden hatten, welche Fragen wir beantworten wollten, und die für die Beantwortung nützlichen Messwerte identifiziert hatten, war es an der Zeit, Google Analytics zu implementieren und mit der Messung zu beginnen.
Die Analyseimplementierung
Wenn Sie Google Analytics bereits verwendet haben, sind Sie wahrscheinlich bereits mit dem empfohlenen JavaScript-Tracking-Snippet vertraut. Sie sieht so aus:
<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>
Mit der ersten Zeile im Code oben wird eine globale ga()
-Funktion initialisiert (sofern sie noch nicht vorhanden ist) und mit der letzten Zeile wird die analytics.js
-Bibliothek asynchron heruntergeladen.
Der mittlere Teil enthält diese beiden Zeilen:
ga('create', 'UA-XXXXX-Y', 'auto');
ga('send', 'pageview');
Mit diesen beiden Befehlen können Sie erfassen, welche Seiten von Besuchern Ihrer Website aufgerufen werden, aber nicht viel mehr. Wenn Sie zusätzliche Nutzerinteraktionen erfassen möchten, müssen Sie dies selbst tun.
Für IOWA wollten wir zwei zusätzliche Dinge erfassen:
- Die verstrichene Zeit zwischen dem ersten Ladevorgang der Seite und der Anzeige von Pixeln auf dem Bildschirm.
- Gibt an, ob ein Service Worker die Seite steuert oder nicht. Mit diesen Informationen konnten wir unsere Berichte segmentieren, um die Ergebnisse mit und ohne Service Worker zu vergleichen.
Zeit bis zum First Paint erfassen
Einige Browser erfassen genau die Zeit, zu der das erste Pixel auf den Bildschirm gezeichnet wird, und stellen diese Zeit den Entwicklern zur Verfügung. Dieser Wert lässt uns im Vergleich zum navigationStart
-Wert, der über die Navigation Timing API zur Verfügung gestellt wird, sehr genau ermitteln, wie viel Zeit zwischen der ersten Anforderung der Seite durch den Nutzer und dem ersten Aufruf der Seite vergangen ist.
Wie bereits erwähnt, ist die Zeit bis zum ersten Mal ein wichtiger Messwert, der gemessen werden sollte, da dies der erste Punkt ist, an dem ein Nutzer die Ladegeschwindigkeit Ihrer Website erlebt. Es ist der erste Eindruck, den die Nutzer erhalten, und ein guter erster Eindruck kann sich positiv auf die restliche Nutzererfahrung auswirken.2
Um den ersten Paint-Wert in Browsern abzurufen, in denen er angezeigt wird, haben wir die Dienstfunktion getTimeToFirstPaintIfSupported
erstellt:
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;
}
}
}
Damit könnten wir jetzt eine weitere Funktion schreiben, die ein ohne Interaktion-Ereignis sendet, dessen Wert die Zeit für die Erstdarstellung ist: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
});
}
}
Nach dem Schreiben dieser beiden Funktionen sieht der Tracking-Code so aus:
// 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();
Beachten Sie, dass je nachdem, wann der obige Code ausgeführt wird, Pixel möglicherweise bereits auf den Bildschirm gezeichnet wurden. Damit dieser Code immer nach dem First Paint ausgeführt wird, haben wir den Aufruf von sendTimeToFirstPaint()
bis nach dem load
-Ereignis verschoben. Wir haben beschlossen, das Senden aller Analysedaten erst nach dem Laden der Seite zu verschieben, um sicherzustellen, dass diese Anfragen nicht mit dem Laden anderer Ressourcen konkurrieren.
// 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();
});
Der Code oben meldet firstpaint
Mal Google Analytics. Das ist aber nur längst nicht alles. Wir mussten noch den Service Worker-Status verfolgen. da wir sonst nicht die First Paint-Zeiten einer Seite, die von einem Service Worker kontrolliert wird, und einer nicht kontrollierten Seite vergleichen können.
Service Worker-Status ermitteln
Um den aktuellen Status des Service Workers zu bestimmen, haben wir eine Dienstprogrammfunktion erstellt, die einen von drei Werten zurückgibt:
- control (gesteuert): Ein Service Worker steuert die Seite. Im Fall von IOWA bedeutet das auch, dass alle Assets im Cache gespeichert wurden und die Seite offline funktioniert.
- supported: Der Browser unterstützt Service Worker, der Service Worker steuert die Seite jedoch noch nicht. Dies ist der erwartete Status für Erstbesucher.
- unsupported: Der Service Worker wird vom Browser des Nutzers nicht unterstützt.
function getServiceWorkerStatus() {
if ('serviceWorker' in navigator) {
return navigator.serviceWorker.controller ? 'controlled' : 'supported';
} else {
return 'unsupported';
}
}
Diese Funktion hat den Service Worker-Status für uns abgerufen. wurde der Status als Nächstes mit den Daten verknüpft, die an Google Analytics gesendet wurden.
Benutzerdefinierte Daten mit benutzerdefinierten Dimensionen erfassen
In Google Analytics haben Sie standardmäßig viele Möglichkeiten, Ihren gesamten Traffic basierend auf Attributen des Nutzers, der Sitzung oder der Interaktion in Gruppen zu unterteilen. Diese Attribute werden als Dimensionen bezeichnet. Für Webentwickler sind häufig Dimensionen wie Browser, Betriebssystem oder Gerätekategorie wichtig.
Der Status des Service Workers ist keine von Google Analytics standardmäßig bereitgestellte Dimension. In Google Analytics können Sie jedoch eigene benutzerdefinierte Dimensionen erstellen und beliebig definieren.
Für IOWA haben wir eine benutzerdefinierte Dimension namens Service Worker Status erstellt und als Umfang Treffer festgelegt, d. h. pro Interaktion.4 Jede benutzerdefinierte Dimension, die Sie in Google Analytics erstellen, erhält einen eindeutigen Index innerhalb dieser Property. Im Tracking-Code können Sie diese Dimension über ihren Index referenzieren. Wenn der Index der soeben erstellten Dimension beispielsweise 1 ist, können wir unsere Logik so aktualisieren, dass das firstpaint
-Ereignis mit dem Service Worker-Status gesendet wird:
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()
});
Das funktioniert, der Status des Service Workers wird jedoch nur mit diesem Ereignis verknüpft. Da der Service Worker-Status für jede Interaktion nützlich sein kann, sollten Sie ihn bei allen Daten angeben, die an Google Analytics gesendet werden.
Damit diese Informationen in alle Treffer einbezogen werden (z.B. alle Seitenaufrufe, Ereignisse usw.), legen wir den Wert der benutzerdefinierten Dimension im Tracker-Objekt selbst fest, bevor Daten an Google Analytics gesendet werden.
ga('set', 'dimension1', getServiceWorkerStatus());
Nach der Festlegung wird dieser Wert mit allen nachfolgenden Treffern für den aktuellen Seitenaufbau gesendet. Wenn der Nutzer die Seite später noch einmal lädt, wird von der Funktion getServiceWorkerStatus()
wahrscheinlich ein neuer Wert zurückgegeben, der für das Tracker-Objekt festgelegt wird.
Ein kurzer Hinweis zur Verständlichkeit und Lesbarkeit des Codes: Da andere Nutzer, die sich diesen Code ansehen, möglicherweise nicht wissen, worauf sich dimension1
bezieht, ist es am besten, eine Variable zu erstellen, die den von analytics.js verwendeten Werten aussagekräftige Dimensionsnamen zuordnet.
// 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();
});
Wie bereits erwähnt, können wir die Dimension Service Worker-Status bei jedem Treffer in Berichten zu beliebigen Messwerten verwenden.
Wie Sie sehen, erfolgten fast 85% aller Seitenaufrufe für IOWA über Browser, die Service Worker unterstützen.
Das Ergebnis: Beantwortung unserer Fragen
Nachdem wir mit der Datenerhebung begonnen hatten, um unsere Fragen zu beantworten, konnten wir Berichte zu diesen Daten erstellen, um die Ergebnisse zu sehen. Hinweis: Alle hier aufgeführten Google Analytics-Daten stellen die tatsächlichen Webzugriffe auf die IOWA-Website vom 16. bis 22. Mai 2016 dar.
Die erste Frage war: Ist das Caching durch den Service Worker leistungsfähiger als die bestehenden HTTP-Caching-Mechanismen, die in allen Browsern verfügbar sind?
Um diese Frage zu beantworten, haben wir einen benutzerdefinierten Bericht erstellt, der den Messwert Durchschn. Seitenladezeit für verschiedene Dimensionen. Dieser Messwert eignet sich gut zur Beantwortung dieser Frage, da das load
-Ereignis erst ausgelöst wird, nachdem alle anfänglichen Ressourcen heruntergeladen wurden. Sie spiegelt also direkt die Gesamtladezeit für alle kritischen Ressourcen der Website wider.5
Wir haben folgende Dimensionen ausgewählt:
- Unsere benutzerdefinierte Dimension Service Worker-Status
- Nutzertyp: Gibt an, ob es sich um den ersten Besuch des Nutzers auf der Website handelt oder er zurückkehrt. Hinweis: Für einen neuen Besucher werden keine Ressourcen im Cache gespeichert, für einen wiederkehrenden Besucher hingegen schon.
- Gerätekategorie: Damit können wir die Ergebnisse für Mobilgeräte und Computer vergleichen.
Um die Möglichkeit zu vermeiden, dass nicht auf den Dienst-Worker bezogene Faktoren unsere Ladezeitergebnisse verfälscht werden, beschränkten wir unsere Abfrage auf Browser, die Service Worker unterstützen.
Wie Sie sehen, wurden Besuche unserer App, die von einem Service Worker gesteuert wurden, viel schneller geladen als nicht kontrollierte Besuche, selbst wenn sie von wiederkehrenden Nutzern stammen, die wahrscheinlich die meisten Ressourcen der Seite im Cache gespeichert hatten. Interessant ist auch, dass Besucher von Mobilgeräten mit Service Workern durchschnittlich schnellere Ladezeiten als neue Desktop-Besucher verzeichneten.
„...Die Besuche unserer App, die von einem Service Worker gesteuert wurden, wurden viel schneller geladen als nicht kontrollierte Besuche.“
Weitere Details finden Sie in den folgenden beiden Tabellen:
Durchschn. Seitenladezeit (Desktop) | |||
---|---|---|---|
Service Worker-Status | Nutzertyp | Durchschn. Seitenladezeit (ms) | Stichprobengröße |
Gesteuert: | Wiederkehrender Besucher | 2568 | 30860 |
Unterstützt | Wiederkehrender Besucher | 3612 | 1289 |
Unterstützt | Neuer Besucher | 4664 | 21991 |
Durchschn. Seitenladezeit (Mobilgeräte) | |||
---|---|---|---|
Service Worker-Status | Nutzertyp | Durchschn. Seitenladezeit (ms) | Stichprobengröße |
Gesteuert: | Wiederkehrender Besucher | 3760 | 8162 |
Unterstützt | Wiederkehrender Besucher | 4843 | 676 |
Unterstützt | Neuer Besucher | 6158 | 5779 |
Sie fragen sich vielleicht, wie es möglich ist, dass sich ein wiederkehrender Besucher, dessen Browser den Service Worker unterstützt, irgendwann in einem nicht kontrollierten Zustand befindet. Hierfür gibt es verschiedene mögliche Erklärungen:
- Der Nutzer hat die Seite beim ersten Besuch verlassen, bevor der Service Worker die Initialisierung abschließen konnte.
- Der Nutzer hat den Service Worker über die Entwicklertools deinstalliert.
Beide Situationen treten relativ selten auf. Anhand der Daten unter Seitenaufbaubeispiel in der vierten Spalte können wir das sehen. Beachten Sie, dass die mittleren Zeilen eine viel kleinere Stichprobe enthalten als die anderen beiden.
Unsere zweite Frage war: Wie wirkt sich der Service Worker auf das Laden der Website aus?
Um diese Frage zu beantworten, haben wir einen weiteren benutzerdefinierten Bericht für den Messwert Durchschn. Ereigniswert und haben die Ergebnisse so gefiltert, dass nur die firstpaint
-Ereignisse enthalten sind. Wir haben die Dimensionen Gerätekategorie und unsere benutzerdefinierte Dimension Service Worker-Status verwendet.
Anders als ich es erwartet hatte, hatte der Service Worker auf Mobilgeräten viel weniger Einfluss auf die Zeit bis zum First Paint als auf den gesamten Seitenaufbau.
„...Der Service Worker hatte auf Mobilgeräten viel weniger Einfluss auf die Zeit bis zum First Paint als auf den gesamten Seitenaufbau.“
Um herauszufinden, warum das so ist, müssen wir die Daten genauer untersuchen. Durchschnittswerte können für allgemeine Übersichten und eine allgemeine Darstellung gut geeignet sein. Um jedoch einen Eindruck davon zu bekommen, wie sich diese Zahlen auf einen Bereich von Nutzern aufschlüsseln, müssen wir uns eine Verteilung von firstpaint
-mal ansehen.
Verteilung eines Messwerts in Google Analytics abrufen
Für die Verteilung der firstpaint
-Werte benötigen wir Zugriff auf die einzelnen Ergebnisse für jedes Ereignis. Leider ist das mit Google Analytics nicht ganz einfach.
Mit Google Analytics können wir einen Bericht nach beliebigen Dimensionen aufschlüsseln, aber nicht nach Messwerten aufschlüsseln. Das heißt nicht, dass es unmöglich ist, sondern bedeutet nur, dass wir unsere Implementierung etwas weiter anpassen mussten, um das gewünschte Ergebnis zu erzielen.
Da die Berichtsergebnisse nur nach Dimensionen aufgeschlüsselt werden können, mussten wir den Messwert (in diesem Fall firstpaint
-mal) als benutzerdefinierte Dimension für das Ereignis festlegen. Dazu haben wir eine weitere benutzerdefinierte Dimension namens Messwert erstellt und die firstpaint
-Tracking-Logik so aktualisiert:
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);
}
}
Die Google Analytics-Weboberfläche bietet derzeit keine Möglichkeit, die Verteilung beliebiger Messwerte zu visualisieren. Mithilfe der Google Analytics Core Reporting API und der Google Charts-Bibliothek könnten wir jedoch die Rohdaten abfragen und dann selbst ein Histogramm erstellen.
Die folgende API-Anfragekonfiguration wurde beispielsweise verwendet, um mit einem nicht kontrollierten Service Worker eine Verteilung von firstpaint
-Werten auf dem Desktop zu erhalten.
{
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'
}
]
}
Diese API-Anfrage gibt ein Array von Werten zurück, die wie folgt aussehen. (Hinweis: Dies sind nur die ersten fünf Ergebnisse.) Die Ergebnisse sind in absteigender Reihenfolge sortiert, sodass diese Zeilen die schnellsten Zeiten darstellen.
API-Antwortergebnisse (erste fünf Zeilen) | |
---|---|
ga:dimension2 | ga:totalEvents |
4 | 3 |
5 | 2 |
6 | 10 |
7 | 8 |
8 | 10 |
Hier ist die Bedeutung dieser Ergebnisse in einfachem Englisch:
- Es gibt 3 Ereignisse, bei denen der
firstpaint
-Wert 4 ms betrug - Es gibt 2 Ereignisse, bei denen der
firstpaint
-Wert 5 ms betrug - Es gibt 10 Ereignisse, bei denen der
firstpaint
-Wert 6 ms betrug - Es gibt 8 Ereignisse, bei denen der
firstpaint
-Wert 7 ms betrug - Es gibt 10 Ereignisse, bei denen der
firstpaint
-value
8 ms betrug - usw.
Aus diesen Ergebnissen können wir den firstpaint
-Wert für jedes einzelne Ereignis extrapolieren und ein Histogramm der Verteilung erstellen. Dies haben wir für jede unserer Abfragen getan.
So sah die Verteilung auf Desktop-Computern mit einem nicht kontrollierten (aber unterstützten) Service Worker aus:
![Zeit bis zur First Paint-Verteilung auf Computern (unterstützt)](https://web.dev/static/case-studies/service-worker-perf/image/time-first-paint-distrib-adc6d60d00c31.png?authuser=6&hl=de)
Der Medianwert für die firstpaint
-Zeit für die obige Verteilung beträgt 912 ms.
Die Form dieser Kurve ist für die Verteilung der Ladezeit recht typisch. Im Gegensatz dazu zeigt das folgende Histogramm die Verteilung von First Paint-Ereignissen für Besuche, bei denen die Seite von einem Service Worker gesteuert wurde.
![Zeit bis zur First Paint-Verteilung auf dem Computer (gesteuert)](https://web.dev/static/case-studies/service-worker-perf/image/time-first-paint-distrib-0b74756b849ee.png?authuser=6&hl=de)
Wenn die Seite von einem Service Worker gesteuert wurde, erlebte er bei vielen Besuchern einen nahezu sofortigen First Paint mit einem Medianwert von 583 ms.
„...als ein Service Worker die Seite gesteuert hat, erlebten viele Besucher einen fast unmittelbaren First Paint...“
Damit Sie einen besseren Überblick über die Unterschiede zwischen diesen beiden Verteilungen erhalten, sehen Sie im nächsten Diagramm eine zusammengeführte Ansicht der beiden. Das Histogramm, das nicht kontrollierte Service Worker-Besuche zeigt, wird über das Histogramm mit kontrollierten Besuchen gelegt, und beide werden über ein Histogramm gelegt, in dem beide kombiniert sind.
![Zeit bis zur First Paint-Verteilung auf Computern](https://web.dev/static/case-studies/service-worker-perf/image/time-first-paint-distrib-5f69da3b18e2c.png?authuser=6&hl=de)
An diesen Ergebnissen fand ich interessant, dass die Verteilung mit einem kontrollierten Service Worker auch nach dem anfänglichen Anstieg eine glockenförmige Kurve aufwies. Ich hatte mit einem großen anfänglichen Anstieg und einem allmählichen Rückgang gerechnet, aber nicht mit einem zweiten Spitzenwert in der Kurve.
Als ich mir die Ursache angesehen habe, habe ich festgestellt, dass der Thread möglicherweise inaktiv ist, obwohl ein Service Worker eine Seite steuert. Der Browser tut dies, um Ressourcen zu sparen. Natürlich müssen nicht alle Service Worker für jede Website, die Sie besucht haben, jederzeit aktiv und einsatzbereit sein. Dies erklärt die Ausdehnung dieser Verteilung. Bei einigen Nutzern trat beim Starten des Service Worker-Threads eine Verzögerung auf.
Wie Sie der Verteilung entnehmen können, stellten Browser mit Service Workern trotz dieser anfänglichen Verzögerung Inhalte schneller bereit als Browser, die das Netzwerk durchqueren.
So sah die Situation auf Mobilgeräten aus:
![Zeit bis zur First Paint-Verteilung auf Mobilgeräten](https://web.dev/static/case-studies/service-worker-perf/image/time-first-paint-distrib-4ae7b2dd6775c.png?authuser=6&hl=de)
Die First Paint-Zeiten nahmen zwar noch deutlich zu, aber der Endwert war ein bisschen größer und länger. Das liegt wahrscheinlich daran, dass das Starten eines inaktiven Service Worker-Threads auf Mobilgeräten länger dauert als auf dem Desktop. Außerdem wird erklärt, warum der Unterschied zwischen der durchschnittlichen firstpaint
-Zeit nicht so groß war, wie ich erwartet hatte (siehe oben).
„...auf Mobilgeräten dauert das Starten eines inaktiven Service Worker-Threads länger als auf dem Computer.“
Hier ist eine Aufschlüsselung dieser Variationen der Medianwerte für die Dauer von First Paint auf Mobilgeräten und Computern, gruppiert nach Service Worker-Status:
Medianwert für die Zeit bis zum ersten Mal (ms) | ||
---|---|---|
Service Worker-Status | Computer | Mobilgeräte |
Gesteuert: | 583 | 1634 |
Unterstützt (nicht kontrolliert) | 912 | 1933 |
Das Erstellen dieser Verteilungsvisualisierungen war zwar etwas aufwändiger als das Erstellen eines benutzerdefinierten Berichts in Google Analytics, aber sie vermitteln uns ein viel besseres Verständnis dafür, wie Service Worker die Leistung unserer Website beeinflussen als nur Durchschnittswerte.
Andere Auswirkungen von Service Workern
Neben den Auswirkungen auf die Leistung beeinflussen Service Worker die Nutzererfahrung auch in mehreren anderen Bereichen, die mit Google Analytics gemessen werden können.
Offlinezugriff
Service Worker ermöglichen Nutzern die Interaktion mit Ihrer Website, während sie offline sind. Auch wenn eine Art Offlinesupport wahrscheinlich für jede progressive Web-App von entscheidender Bedeutung ist, hängt es vor allem davon ab, wie hoch die Offlinenutzung ist, um zu bestimmen, wie wichtig diese für Ihren Fall ist. Aber wie messen wir das?
Für das Senden von Daten an Google Analytics ist eine Internetverbindung erforderlich. Die Daten müssen jedoch nicht zum exakten Zeitpunkt gesendet werden, zu dem die Interaktion stattgefunden hat. In Google Analytics wird das nachträgliche Senden von Interaktionsdaten unterstützt. Dazu wird über den Parameter qt
ein Zeitversatz angegeben.
Seit zwei Jahren verwendet IOWA ein Service Worker-Skript, das fehlgeschlagene Treffer für Google Analytics erkennt, wenn der Nutzer offline ist, und sie später mit dem Parameter qt
noch einmal abspielt.
Um zu ermitteln, ob der Nutzer online oder offline war, haben wir die benutzerdefinierte Dimension Online erstellt und auf den Wert navigator.onLine
festgelegt. Anschließend wurden die Ereignisse online
und offline
erfasst und die Dimension entsprechend aktualisiert.
Um ein Gefühl dafür zu bekommen, wie häufig ein Nutzer offline ist, während er IOWA verwendet, haben wir ein Segment erstellt, das Nutzer mit mindestens einer Offline-Interaktion angesprochen hat. Es stellte sich heraus, dass das fast 5% der Nutzer waren.
Push-Benachrichtigungen
Mit Service Workern können Nutzer dem Erhalt von Push-Benachrichtigungen zustimmen. In IOWA wurden Nutzer vor dem Beginn einer Sitzung in ihrem Zeitplan benachrichtigt.
Wie bei jeder Art von Benachrichtigung ist es wichtig, ein Gleichgewicht zwischen einem Mehrwert für den Nutzer und dem Fehlen von Anzeigen zu finden. Um besser zu verstehen, was passiert, ist es wichtig zu wissen, ob Nutzer sich für den Erhalt dieser Benachrichtigungen angemeldet haben, ob sie mit ihnen interagieren, wenn sie sie besuchen, und ob Nutzer, die zuvor zugestimmt haben, ihre Einstellungen ändern und deaktivieren.
In IOWA haben wir nur Benachrichtigungen gesendet, die sich auf den personalisierten Zeitplan des Nutzers beziehen – etwas, das nur angemeldete Nutzer erstellen konnten. Dadurch wurde die Gruppe der Nutzer, die Benachrichtigungen erhalten konnten, auf angemeldete Nutzer beschränkt (erfasst über die benutzerdefinierte Dimension Angemeldet), deren Browser Push-Benachrichtigungen unterstützt haben (die über eine andere benutzerdefinierte Dimension namens Berechtigung zum Senden von Benachrichtigungen erfasst werden).
Der folgende Bericht basiert auf dem Messwert Nutzer und unserer benutzerdefinierten Dimension „Benachrichtigungsberechtigung“. Er ist nach Nutzern segmentiert, die sich irgendwann angemeldet haben und deren Browser Push-Benachrichtigungen unterstützen.
Mehr als die Hälfte unserer angemeldeten Nutzer hat sich für den Erhalt von Push-Benachrichtigungen entschieden.
App-Installationsbanner
Wenn eine progressive Web-App die Kriterien erfüllt und von einem Nutzer häufig verwendet wird, wird diesem Nutzer unter Umständen ein App-Installationsbanner angezeigt, in dem er aufgefordert wird, die App zu seinem Startbildschirm hinzuzufügen.
In IOWA haben wir mit dem folgenden Code verfolgt, wie oft dem Nutzer diese Aufforderungen angezeigt wurden (und ob sie akzeptiert wurden):
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
});
});
});
Etwa 10% der Nutzer, die ein App-Installationsbanner gesehen haben, entschieden sich dafür, es zu ihrem Startbildschirm hinzuzufügen.
Mögliche Verbesserungen beim Tracking (nächstes Mal)
Die in diesem Jahr bei IOWA gesammelten Analysedaten waren von unschätzbarem Wert. Aber die Rückschau birgt immer wieder Lücken und Möglichkeiten, die Dinge für das nächste Mal zu verbessern. Nach Abschluss der diesjährigen Analyse hätten wir gerne zwei Dinge anders gemacht als Leser, die nach einer ähnlichen Strategie suchen würden:
1. Weitere Ereignisse im Zusammenhang mit dem Ladevorgang erfassen
Wir haben mehrere Ereignisse erfasst, die einem technischen Messwert entsprechen (z. B. HTMLImportsLoaded, WebComponentsReady usw.). Da ein Großteil des Ladevorgangs asynchron ausgeführt wurde, entsprach der Zeitpunkt, an dem diese Ereignisse ausgelöst wurden, nicht unbedingt mit einem bestimmten Moment im gesamten Ladevorgang.
Das primäre Ladeereignis, das wir nicht erfassen, ist der Punkt, an dem der Ladebildschirm verschwindet und der Nutzer den Seiteninhalt sehen kann.
2. Analyse-Client-ID in IndexedDB speichern
Standardmäßig speichert analytics.js das Client-ID-Feld in den Cookies des Browsers. Service Worker-Skripts können nicht auf Cookies zugreifen.
Dies stellte ein Problem für uns dar, als wir versucht haben, die Benachrichtigungsverfolgung zu implementieren. Wir wollten jedes Mal ein Ereignis vom Service Worker (über das Measurement Protocol) senden, wenn eine Benachrichtigung an einen Nutzer gesendet wird, und dann den Erfolg der erneuten Interaktion dieser Benachrichtigung erfassen, wenn der Nutzer darauf geklickt hat und zur App zurückkehrt.
Wir konnten den Erfolg von Benachrichtigungen im Allgemeinen über den Kampagnenparameter utm_source
erfassen, konnten aber keine bestimmte Sitzung für erneute Interaktion mit einem bestimmten Nutzer verknüpfen.
Um diese Einschränkung zu umgehen, hätte das Service Worker-Skript die Client-ID über IndexedDB in unserem Tracking-Code gespeichert.
3. Der Service Worker kann den Online-/Offlinestatus melden.
Durch die Untersuchung von navigator.onLine
kannst du feststellen, ob dein Browser eine Verbindung zum Router oder Local Area Network herstellen kann. Es lässt sich jedoch nicht unbedingt sagen, ob der Nutzer eine echte Verbindung hat. Und da unser Offline-Analyse-Service-Worker-Skript einfach fehlgeschlagene Treffer erneut abspielt (ohne sie zu ändern oder als fehlgeschlagen zu markieren), haben wir unsere Offline-Nutzung wahrscheinlich nicht ausreichend gemeldet.
Zukünftig sollten wir sowohl den Status von navigator.onLine
als auch feststellen, ob der Treffer vom Service Worker aufgrund eines anfänglichen Netzwerkfehlers noch einmal wiedergegeben wurde. Dadurch erhalten wir ein genaueres Bild der tatsächlichen Offlinenutzung.
Zusammenfassung
Diese Fallstudie hat gezeigt, dass die Ladeleistung der Google I/O-Webapp in einer Vielzahl von Browsern, Netzwerken und Geräten durch den Einsatz von Service Workern tatsächlich verbessert wurde. Außerdem hat sich gezeigt, dass die Verteilung der Lastdaten für eine Vielzahl von Browsern, Netzwerken und Geräten deutlich mehr Erkenntnisse darüber liefert, wie diese Technologie reale Szenarien handhabt, und Leistungsmerkmale entdecken, die Sie möglicherweise nicht erwartet hätten.
Hier einige der wichtigsten Erkenntnisse aus der IOWA-Studie:
- Im Durchschnitt wurden Seiten bei neuen und wiederkehrenden Besuchern deutlich schneller geladen, wenn sie von einem Service Worker gesteuert wurden als ohne Service Worker.
- Besuche von Seiten, die von einem Service Worker gesteuert werden, wurden für viele Nutzer beinahe sofort geladen.
- Der Start der Service Worker dauerte bei Inaktivität eine Weile. Ein inaktiver Service Worker schnitt aber trotzdem besser ab als kein Service Worker.
- Ein inaktiver Service Worker startete auf Mobilgeräten länger als auf dem Computer.
Während die in einer bestimmten Anwendung beobachteten Leistungssteigerungen im Allgemeinen nützlich sind, um der größeren Entwickler-Community zu berichten, ist es wichtig zu bedenken, dass diese Ergebnisse spezifisch für die Art der Website sind, die IOWA (eine Veranstaltungswebsite) ist, und die Art der Zielgruppe, die IOWA hat (hauptsächlich Entwickler).
Wenn Sie Service Worker in Ihrer Anwendung implementieren, ist es wichtig, dass Sie Ihre eigene Messstrategie implementieren, damit Sie Ihre eigene Leistung bewerten und zukünftige Regressionen verhindern können. Wenn ja, teilen Sie Ihre Ergebnisse bitte mit, damit alle davon profitieren können!
Fußnoten
- Es ist nicht ganz fair, die Leistung unserer Service Worker-Cache-Implementierung mit der Leistung unserer Website nur mit dem HTTP-Cache zu vergleichen. Da wir IOWA für Service Worker optimieren wollten, haben wir nicht viel Zeit für die Optimierung des HTTP-Cache aufgewendet. Wenn wir es so hätten, wären die Ergebnisse wahrscheinlich anders gewesen. Weitere Informationen zur Optimierung Ihrer Website für den HTTP-Cache finden Sie unter Inhalte effizient optimieren.
- Je nachdem, wie Ihre Website die Stile und Inhalte lädt, ist es möglich, dass der Browser Daten übertragen kann, bevor Inhalte oder Stile verfügbar sind. In solchen Fällen kann
firstpaint
einem leeren weißen Bildschirm entsprechen. Wenn dufirstpaint
verwendest, solltest du darauf achten, dass es zu einem aussagekräftigen Punkt beim Laden der Ressourcen deiner Website passt. - Technisch gesehen könnten wir einen Timing-Treffer senden, der standardmäßig keine Interaktion ist, um diese Informationen anstelle eines Ereignisses zu erfassen. Timing-Treffer wurden in Google Analytics hinzugefügt, um Lastmesswerte wie diese zu erfassen: Allerdings werden Timingtreffer bei der Verarbeitung häufig erfasst und ihre Werte können nicht in Segmenten verwendet werden. Angesichts dieser aktuellen Einschränkungen sind Ereignisse ohne Interaktion besser geeignet.
- In der Analytics-Hilfe finden Sie im Abschnitt Benutzerdefinierte Dimension weitere Informationen dazu, in welchem Umfang eine benutzerdefinierte Dimension in Google Analytics zugewiesen werden sollte. Außerdem ist es wichtig, das Google Analytics-Datenmodell zu verstehen, das aus Nutzern, Sitzungen und Interaktionen (Treffern) besteht. Weitere Informationen finden Sie in der Analytics Academy-Lektion zum Google Analytics-Datenmodell.
- Ressourcen, die nach dem Ladeereignis verzögert geladen werden, werden nicht berücksichtigt.