Einer der wichtigsten Vorteile von Dienstprogrammen (zumindest aus Leistungsperspektive) ist die Möglichkeit, das Caching von Assets proaktiv zu steuern. Eine Webanwendung, die alle erforderlichen Ressourcen im Cache speichern kann, sollte für wiederkehrende Besucher wesentlich schneller laden. Aber wie sehen diese Verbesserungen für echte Nutzer aus? Und wie lässt sich das überhaupt messen?
Die Google I/O-Web-App (IOWA) ist eine progressive Web-App, bei der die meisten neuen Funktionen von Dienst-Workern genutzt wurden, um Nutzern eine umfangreiche, app-ähnliche Umgebung zu bieten. Außerdem nutzte das Unternehmen Google Analytics, um wichtige Leistungsdaten und Nutzungsmuster seiner großen und vielfältigen Nutzergruppe zu erfassen.
In dieser Fallstudie wird untersucht, wie IOWA mit Google Analytics wichtige Fragen zur Leistung beantwortet und die tatsächlichen Auswirkungen von Dienstprogrammen ermittelt hat.
Mit den Fragen beginnen
Wenn Sie Analysen auf einer Website oder in einer Anwendung implementieren, sollten Sie zuerst die Fragen ermitteln, die Sie anhand der erfassten Daten beantworten möchten.
Wir hatten mehrere Fragen, die wir beantworten wollten. Für diese Fallstudie konzentrieren wir uns jedoch auf zwei der interessanteren.
1. Ist das Caching von Service Workern leistungsfähiger als die vorhandenen HTTP-Caching-Mechanismen, die in allen Browsern verfügbar sind?
Wir gehen davon aus, dass Seiten für wiederkehrende Besucher schneller geladen werden als für neue Besucher, da Browser Anfragen im Cache speichern und bei wiederholten Besuchen sofort ausliefern können.
Dienstprogramme bieten alternative Caching-Funktionen, mit denen Entwickler genau steuern können, was und wie gecacht wird. Bei IOWA haben wir unsere Service Worker-Implementierung so optimiert, dass jedes Asset im Cache gespeichert wird, damit wiederkehrende Besucher die App vollständig offline nutzen können.
Aber wäre das besser als das, was der Browser standardmäßig bereits tut? Und wenn ja, wie viel besser? 1
2. Wie wirkt sich ein Service Worker auf das Laden der Website aus?
Mit anderen Worten: Wie schnell fühlt sich das Laden der Website an, unabhängig von den tatsächlichen Ladezeiten, die anhand herkömmlicher Messwerte für das Laden von Seiten gemessen werden?
Fragen zu den Eindrücken von Nutzern zu beantworten, ist natürlich keine leichte Aufgabe und kein Messwert kann ein solches subjektives Gefühl perfekt darstellen. Es gibt jedoch definitiv einige Messwerte, die besser sind als andere. Daher ist es wichtig, die richtigen auszuwählen.
Den richtigen Messwert auswählen
In Google Analytics werden standardmäßig die Seitenladezeiten (über die Navigation Timing API) für 1% der Websitebesucher erfasst. Diese Daten sind über Messwerte wie „Durchschnittliche Seitenladezeit“ verfügbar.
Der Messwert Durchschnittliche Seitenladezeit ist ein guter Messwert, um unsere erste Frage zu beantworten, aber nicht besonders gut geeignet, um die zweite zu beantworten. Zum einen entspricht das Ereignis load
nicht unbedingt dem Moment, in dem der Nutzer tatsächlich mit der App interagieren kann. Außerdem kann es sein, dass zwei Apps mit der exakt gleichen Ladezeit für den Nutzer ganz unterschiedlich erscheinen. Eine Website mit einem Splashscreen oder einem Ladeindikator wird beispielsweise wahrscheinlich als viel schneller empfunden als eine Website, auf der mehrere Sekunden lang nur eine leere Seite angezeigt wird.
In IOWA haben wir eine Countdown-Animation auf dem Splashscreen verwendet, die meiner Meinung nach sehr gut dazu beigetragen hat, die Nutzer zu unterhalten, während der Rest der App im Hintergrund geladen wurde. Daher ist es viel sinnvoller, die Zeit zu messen, die vergeht, bis der Splashscreen erscheint, um die wahrgenommene Ladeleistung zu messen. Wir haben den Messwert Zeit bis zur ersten Darstellung ausgewählt, um diesen Wert zu erhalten.
Nachdem wir uns für die Fragen entschieden und die Messwerte identifiziert hatten, die für die Beantwortung hilfreich sind, war es an der Zeit, Google Analytics zu implementieren und mit der Analyse zu beginnen.
Die Analyseimplementierung
Wenn Sie Google Analytics bereits verwendet haben, sind Sie wahrscheinlich 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>
In der ersten Zeile des obigen Codes wird eine globale ga()
-Funktion initialisiert (falls sie noch nicht vorhanden ist). In der letzten Zeile wird die analytics.js
-Bibliothek asynchron heruntergeladen.
Der mittlere Teil enthält die folgenden beiden Zeilen:
ga('create', 'UA-XXXXX-Y', 'auto');
ga('send', 'pageview');
Mit diesen beiden Befehlen können Sie zwar erfassen, welche Seiten von Nutzern besucht werden, die Ihre Website aufrufen, aber nicht viel mehr. Wenn Sie zusätzliche Nutzerinteraktionen erfassen möchten, müssen Sie dies selbst tun.
Für IOWA wollten wir zwei weitere Dinge erfassen:
- Die Zeitspanne zwischen dem Beginn des Ladens der Seite und dem Zeitpunkt, zu dem Pixel auf dem Bildschirm erscheinen.
- Gibt an, ob die Seite von einem Service Worker gesteuert wird. Mit diesen Informationen konnten wir unsere Berichte segmentieren, um die Ergebnisse mit und ohne Service Worker zu vergleichen.
Time to First Paint erfassen
Einige Browser erfassen die genaue Zeit, zu der das erste Pixel auf dem Bildschirm dargestellt wird, und stellen diese Zeit Entwicklern zur Verfügung. Dieser Wert in Kombination mit dem navigationStart
-Wert, der über die Navigation Timing API bereitgestellt wird, gibt Aufschluss darüber, wie viel Zeit zwischen dem Zeitpunkt vergangen ist, zu dem der Nutzer die Seite angefordert hat, und dem Zeitpunkt, zu dem er etwas gesehen hat.
Wie bereits erwähnt, ist der Time to First Paint ein wichtiger Messwert, da er der erste Punkt ist, an dem Nutzer die Ladegeschwindigkeit Ihrer Website wahrnehmen. Es ist der erste Eindruck, den Nutzer erhalten, und ein guter erster Eindruck kann sich positiv auf die restliche Nutzererfahrung auswirken.2
Um den ersten Paint-Wert in Browsern abzurufen, die ihn bereitstellen, haben wir die Dienstprogrammfunktion 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önnen wir jetzt eine weitere Funktion schreiben, die ein Nicht-Interaktionsereignis sendet, wobei die Zeit bis zur ersten Darstellung als Wert verwendet wird: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
});
}
}
Nachdem wir beide Funktionen geschrieben haben, sieht unser 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();
Je nachdem, wann der Code oben ausgeführt wird, wurden möglicherweise bereits Pixel auf dem Bildschirm gerendert. Damit dieser Code immer nach dem ersten Mal „paint“ ausgeführt wird, haben wir den Aufruf von sendTimeToFirstPaint()
auf nach dem Ereignis load
verschoben. Wir haben uns entschieden, das Senden aller Analysedaten bis nach dem Laden der Seite zu verschieben, damit 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();
});
Mit dem Code oben wird firstpaint
Mal an Google Analytics gesendet. Das ist aber nur die halbe Wahrheit. Wir mussten jedoch weiterhin den Status des Service Workers erfassen, da wir sonst die Zeit bis zur ersten Darstellung einer von einem Service Worker gesteuerten Seite nicht mit der einer nicht gesteuerten Seite vergleichen konnten.
Service Worker-Status ermitteln
Um den aktuellen Status des Dienstarbeiters zu ermitteln, haben wir eine Dienstfunktion erstellt, die einen der drei Werte zurückgibt:
- controlled: Die Seite wird von einem Service Worker gesteuert. 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, aber die Seite wird noch nicht vom Service Worker gesteuert. Das ist der erwartete Status für Erstbesucher.
- unsupported: Der Browser des Nutzers unterstützt keinen Service Worker.
function getServiceWorkerStatus() {
if ('serviceWorker' in navigator) {
return navigator.serviceWorker.controller ? 'controlled' : 'supported';
} else {
return 'unsupported';
}
}
Über diese Funktion haben wir den Status des Dienstarbeiters abgerufen. Im nächsten Schritt mussten wir diesen Status mit den Daten verknüpfen, die wir an Google Analytics gesendet haben.
Benutzerdefinierte Daten mit benutzerdefinierten Dimensionen erfassen
In Google Analytics haben Sie standardmäßig viele Möglichkeiten, den gesamten Traffic in Gruppen aufzuteilen, die auf Nutzer-, Sitzungs- oder Interaktionsattributen basieren. Diese Attribute werden als Dimensionen bezeichnet. Gängige Dimensionen für Webentwickler sind beispielsweise Browser, Betriebssystem oder Gerätekategorie.
Der Status des Dienstarbeiters ist keine Standarddimension in Google Analytics. Sie können jedoch eigene benutzerdefinierte Dimensionen erstellen und nach Belieben definieren.
Für IOWA haben wir die benutzerdefinierte Dimension Service Worker Status erstellt und ihren Gültigkeitsbereich auf Aufruf (d. h. pro Interaktion) festgelegt.4 Jede benutzerdefinierte Dimension, die Sie in Google Analytics erstellen, erhält einen eindeutigen Index innerhalb dieser Property. In Ihrem Tracking-Code können Sie auf diese Dimension anhand ihres Index verweisen. Wenn der Index der gerade erstellten Dimension beispielsweise 1 wäre, könnten wir unsere Logik so aktualisieren, dass das Ereignis firstpaint
mit dem Status des Dienstarbeiters 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, aber der Status des Dienstarbeiters wird nur mit diesem bestimmten Ereignis verknüpft. Da der Status des Dienst-Workers für jede Interaktion nützlich sein kann, sollten Sie ihn in alle an Google Analytics gesendeten Daten aufnehmen.
Damit diese Informationen in alle Treffer aufgenommen werden (z.B. alle Seitenaufrufe, Ereignisse usw.), legen wir den Wert der benutzerdefinierten Dimension auf dem Tracker-Objekt selbst fest, bevor Daten an Google Analytics gesendet werden.
ga('set', 'dimension1', getServiceWorkerStatus());
Einmal festgelegt, wird dieser Wert mit allen nachfolgenden Treffern für das aktuelle Seitenladevorgang gesendet. Wenn der Nutzer die Seite später noch einmal lädt, wird wahrscheinlich ein neuer Wert von der getServiceWorkerStatus()
-Funktion zurückgegeben und dieser Wert wird auf dem Tracker-Objekt festgelegt.
Hinweis zur Klarheit und Lesbarkeit des Codes: Da andere Personen, die sich diesen Code ansehen, möglicherweise nicht wissen, worauf sich dimension1
bezieht, sollten Sie immer eine Variable erstellen, die aussagekräftige Dimensionenamen den Werten zuordnet, die in analytics.js verwendet werden.
// 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 Dienst-Worker-Status mit jedem Treffer senden und dann in Berichten für jeden Messwert verwenden.
Wie Sie sehen, wurden fast 85% aller Seitenaufrufe für IOWA über Browser erzielt, die Service Worker unterstützen.
Die Ergebnisse: Antworten auf unsere Fragen
Nachdem wir damit begonnen hatten, Daten zu erheben, um unsere Fragen zu beantworten, konnten wir Berichte zu diesen Daten erstellen, um die Ergebnisse zu sehen. Hinweis: Alle hier gezeigten Google Analytics-Daten spiegeln den tatsächlichen Webtraffic auf der IOWA-Website vom 16. bis 22. Mai 2016 wider.
Die erste Frage, die wir uns stellten, war: Ist das Caching von Dienstmitarbeitern leistungsfähiger als die vorhandenen HTTP-Caching-Mechanismen, die in allen Browsern verfügbar sind?
Um diese Frage zu beantworten, haben wir einen benutzerdefinierten Bericht erstellt, in dem der Messwert Durchschnittliche Seitenladezeit für verschiedene Dimensionen untersucht wurde. Dieser Messwert eignet sich gut, um diese Frage zu beantworten, da das Ereignis load
erst ausgelöst wird, nachdem alle anfänglichen Ressourcen heruntergeladen wurden. Sie entspricht also direkt der Gesamtladezeit für alle kritischen Ressourcen der Website.5
Wir haben folgende Dimensionen ausgewählt:
- Die benutzerdefinierte Dimension Service Worker-Status
- Nutzertyp: Gibt an, ob es sich um den ersten Besuch des Nutzers auf der Website handelt oder ob er ein wiederkehrender Nutzer ist. Hinweis: Bei einem neuen Besucher sind keine Ressourcen im Cache gespeichert, bei einem wiederkehrenden Besucher möglicherweise schon.
- Gerätekategorie, mit der sich die Ergebnisse für Mobilgeräte und Computer vergleichen lassen
Um die Möglichkeit auszuschließen, dass nicht mit Service Workern zusammenhängende Faktoren unsere Ergebnisse zur Ladezeit verfälschen, haben wir unsere Abfrage auf Browser beschränkt, die Service Worker unterstützen.
Wie Sie sehen, wurden Besuche unserer App, die von einem Service Worker gesteuert wurden, deutlich schneller geladen als nicht gesteuerte Besuche, selbst solche von wiederkehrenden Nutzern, bei denen die meisten Ressourcen der Seite wahrscheinlich im Cache gespeichert waren. Interessant ist auch, dass die Seiten auf Mobilgeräten mit einem Service Worker im Durchschnitt schneller geladen wurden als auf Computern.
„…besuche unserer App, die von einem Service Worker gesteuert werden, wurden deutlich schneller geladen als nicht gesteuerte Besuche…“
Weitere Informationen finden Sie in den folgenden beiden Tabellen:
Durchschnittliche Seitenladezeit (Computer) | |||
---|---|---|---|
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 |
Durchschnittliche 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 ein wiederkehrender Besucher, dessen Browser Service Worker unterstützt, sich in einem nicht kontrollierten Zustand befindet. Dafür gibt es verschiedene mögliche Gründe:
- Der Nutzer hat die Seite beim ersten Besuch verlassen, bevor der Service Worker die Initialisierung abschließen konnte.
- Der Nutzer hat den Dienst-Worker über die Entwicklertools deinstalliert.
Beide Situationen sind relativ selten. Das sehen wir in den Daten an den Werten für Seitenladezeit – Beispiel in der vierten Spalte. Beachten Sie, dass die mittleren Zeilen eine viel kleinere Stichprobe als die anderen beiden haben.
Unsere zweite Frage lautete: Wie wirken sich 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 erstellt und die Ergebnisse so gefiltert, dass nur unsere firstpaint
-Ereignisse enthalten waren. Wir haben die Dimensionen Gerätekategorie und die benutzerdefinierte Dimension Status des Dienst-Workers verwendet.
Anders als erwartet, hatte der Service Worker auf Mobilgeräten viel weniger Auswirkungen auf die Time to First Paint als auf das Gesamtladen der Seite.
„…Service Worker auf Mobilgeräten hatten einen viel geringeren Einfluss auf die Time to First Paint als auf das Gesamtladen der Seite.“
Um herauszufinden, warum das so ist, müssen wir uns die Daten genauer ansehen. Durchschnitte eignen sich gut für einen allgemeinen Überblick. Um jedoch wirklich zu verstehen, wie sich diese Zahlen auf verschiedene Nutzer verteilen, müssen wir uns eine Verteilung von firstpaint
Mal ansehen.
Verteilung eines Messwerts in Google Analytics abrufen
Um die Verteilung der firstpaint
-mal zu erhalten, benötigen wir Zugriff auf die einzelnen Ergebnisse für jedes Ereignis. Leider ist das in Google Analytics nicht ganz einfach.
In Google Analytics können wir Berichte nach beliebigen Dimensionen aufschlüsseln, aber nicht nach Messwerten. Das bedeutet nicht, dass es unmöglich ist, sondern nur, dass wir unsere Implementierung etwas anpassen mussten, um das gewünschte Ergebnis zu erzielen.
Da Berichtsergebnisse nur nach Dimensionen aufgeschlüsselt werden können, mussten wir den Messwert (in diesem Fall firstpaint
„Zeit“) als benutzerdefinierte Dimension für das Ereignis festlegen. Dazu haben wir eine weitere benutzerdefinierte Dimension namens Messwert erstellt und die firstpaint
-Trackinglogik 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 Messwertwerte zu visualisieren. Mithilfe der Google Analytics Core Reporting API und der Google Charts-Bibliothek können wir jedoch die Rohergebnisse abfragen und dann selbst ein Histogramm erstellen.
Mit der folgenden API-Anfragekonfiguration wurde beispielsweise eine Verteilung der firstpaint
-Werte auf dem Computer mit einem nicht gesteuerten Dienstworker abgerufen.
{
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, das so aussieht (Hinweis: Dies sind nur die ersten fünf Ergebnisse). Die Ergebnisse sind von klein nach groß sortiert. Diese Zeilen stehen also für die schnellsten Zeiten.
API-Antwortergebnisse (erste fünf Zeilen) | |
---|---|
ga:dimension2 | ga:totalEvents |
4 | 3 |
5 | 2 |
6 | 10 |
7 | 8 |
8 | 10 |
Das bedeutet Folgendes:
- Bei 3 Ereignissen betrug der Wert für
firstpaint
4 ms. - Bei zwei Ereignissen betrug der Wert für
firstpaint
5 ms. - Bei 10 Ereignissen betrug der
firstpaint
-Wert 6 ms. - Bei 8 Ereignissen betrug der Wert für
firstpaint
7 ms. - Bei 10 Ereignissen betrug die
firstpaint
value
8 ms. - usw.
Anhand dieser Ergebnisse können wir den firstpaint
-Wert für jedes einzelne Ereignis extrapolieren und ein Histogramm der Verteilung erstellen. Wir haben dies für jede der ausgeführten Abfragen getan.
So sah die Bereitstellung auf dem Computer mit einem nicht gesteuerten (aber unterstützten) Service Worker aus:
Die Medianzeit für firstpaint
für die obige Verteilung beträgt 912 ms.
Die Form dieser Kurve ist für die Verteilung der Ladezeiten recht typisch. Im Vergleich dazu zeigt das folgende Histogramm die Verteilung der First Paint-Ereignisse für Besuche, bei denen die Seite von einem Service Worker gesteuert wurde.
Beachten Sie, dass bei der Steuerung der Seite durch einen Service Worker viele Besucher eine nahezu sofortige erste Darstellung mit einem Median von 583 ms erlebten.
„…wenn ein Service Worker die Seite steuerte, konnten viele Besucher die Seite fast sofort sehen…“
Im nächsten Diagramm sehen Sie eine zusammengeführte Ansicht der beiden Verteilungen, um einen besseren Vergleich zu ermöglichen. Das Histogramm mit den nicht kontrollierten Service Worker-Besuchen wird über dem Histogramm mit den kontrollierten Besuchen eingeblendet. Beide werden über einem Histogramm eingeblendet, das beide zusammenfasst.
Interessant fand ich, dass die Verteilung mit einem kontrollierten Dienstprogramm nach dem anfänglichen Anstieg immer noch eine Glockenkurve aufwies. Ich hatte einen großen anfänglichen Anstieg und dann einen allmählichen Rückgang erwartet, aber keinen zweiten Höhepunkt in der Kurve.
Bei der Suche nach der Ursache habe ich festgestellt, dass ein Service Worker zwar eine Seite steuern kann, sein Thread aber inaktiv sein kann. Der Browser tut dies, um Ressourcen zu sparen. Natürlich müssen nicht alle Service Worker für jede Website, die Sie jemals besucht haben, aktiv und sofort einsatzbereit sein. Dies erklärt den Schwanz der Verteilung. Bei einigen Nutzern kam es zu einer Verzögerung beim Starten des Service Worker-Threads.
Wie Sie an der Verteilung sehen können, wurden Inhalte mit Browsern mit Service Worker trotz dieser anfänglichen Verzögerung schneller bereitgestellt als mit Browsern, die das Netzwerk nutzen.
So sah es auf Mobilgeräten aus:
Die Zeit bis zur ersten Farbausgabe konnte zwar deutlich verkürzt werden, die Wartezeit war aber immer noch recht lang. Das liegt wahrscheinlich daran, dass das Starten eines inaktiven Service Worker-Threads auf Mobilgeräten länger dauert als auf dem Computer. Außerdem erklärt es, 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 Schwankungen der medianen First Paint-Zeiten auf Mobilgeräten und Computern nach Service Worker-Status:
Medianwert für die Zeit bis zur ersten Darstellung (ms) | ||
---|---|---|
Service Worker-Status | Computer | Mobilgeräte |
Gesteuert: | 583 | 1634 |
Unterstützt (nicht steuerbar) | 912 | 1933 |
Die Erstellung dieser Verteilungsvisualisierungen hat zwar etwas mehr Zeit und Mühe gekostet als das Erstellen eines benutzerdefinierten Berichts in Google Analytics, aber sie geben uns ein viel besseres Gefühl dafür, wie sich Service Worker auf die Leistung unserer Website auswirken, als nur Durchschnittswerte.
Weitere Auswirkungen von Service Workern
Neben der Leistungsauswirkung wirken sich Service Worker auch auf andere Weisen auf die Nutzerfreundlichkeit aus, die mit Google Analytics gemessen werden können.
Offlinezugriff
Mit Service Workers können Nutzer auch offline mit Ihrer Website interagieren. Eine Art Offline-Support ist für jede progressive Webanwendung wahrscheinlich unerlässlich. Wie wichtig er in Ihrem Fall ist, hängt jedoch weitgehend davon ab, wie oft die Website offline genutzt wird. Aber wie messen wir das?
Für das Senden von Daten an Google Analytics ist eine Internetverbindung erforderlich. Die Daten müssen jedoch nicht genau zum Zeitpunkt der Interaktion gesendet werden. In Google Analytics können Interaktionsdaten nachträglich gesendet werden. Dazu müssen Sie einen Zeitversatz angeben (über den Parameter qt
).
In den letzten zwei Jahren verwendet IOWA ein Service Worker-Script, das fehlgeschlagene Treffer in Google Analytics erkennt, wenn der Nutzer offline ist, und sie später mit dem Parameter qt
noch einmal abspielt.
Um zu erfassen, ob der Nutzer online oder offline war, haben wir die benutzerdefinierte Dimension Online erstellt und ihr den Wert navigator.onLine
zugewiesen. Anschließend haben wir auf die Ereignisse online
und offline
gewartet und die Dimension entsprechend aktualisiert.
Um zu erfahren, wie häufig Nutzer bei der Nutzung von IOWA offline waren, haben wir ein Segment erstellt, das auf Nutzer mit mindestens einer Offlineinteraktion ausgerichtet war. Es stellte sich heraus, dass es sich um fast 5% der Nutzer handelte.
Push-Benachrichtigungen
Mit Service Workern können Nutzer Push-Benachrichtigungen aktivieren. In IOWA wurden Nutzer benachrichtigt, wenn eine Sitzung in ihrem Zeitplan kurz bevorstand.
Wie bei jeder anderen Art von Benachrichtigung ist es wichtig, das richtige Gleichgewicht zwischen Nützlichkeit und Belästigung zu finden. Um besser nachvollziehen zu können, was passiert, ist es wichtig zu verfolgen, ob Nutzer diese Benachrichtigungen aktivieren, ob sie mit ihnen interagieren, wenn sie eingehen, und ob Nutzer, die sie zuvor aktiviert haben, ihre Einstellung ändern und sie deaktivieren.
In Iowa wurden nur Benachrichtigungen zum personalisierten Zeitplan des Nutzers gesendet, den nur angemeldete Nutzer erstellen konnten. Dadurch konnten Benachrichtigungen nur noch an angemeldete Nutzer gesendet werden, deren Browser Push-Benachrichtigungen unterstützten (gemessen über die benutzerdefinierte Dimension Benachrichtigungsberechtigung).
Der folgende Bericht basiert auf dem Messwert Nutzer und der benutzerdefinierten Dimension „Benachrichtigungsberechtigung“. Er ist nach Nutzern segmentiert, die sich einmal angemeldet haben und deren Browser Push-Benachrichtigungen unterstützen.
Es freut uns, dass mehr als die Hälfte unserer angemeldeten Nutzer Push-Benachrichtigungen erhalten möchte.
App-Installationsbanner
Wenn eine progressive Web-App die Kriterien erfüllt und von einem Nutzer häufig verwendet wird, wird diesem Nutzer möglicherweise ein App-Installationsbanner angezeigt, in dem er aufgefordert wird, die App seinem Startbildschirm hinzuzufügen.
In IOWA haben wir mit dem folgenden Code erfasst, wie oft diese Prompts den Nutzern 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
});
});
});
Von den Nutzern, die ein Banner für die App-Installation gesehen haben, haben etwa 10% die App ihrem Startbildschirm hinzugefügt.
Mögliche Tracking-Verbesserungen (fürs nächste Mal)
Die Analysedaten, die wir dieses Jahr von IOWA erfasst haben, waren sehr wertvoll. Aber im Nachhinein werden immer Lücken und Möglichkeiten deutlich, wie man es beim nächsten Mal besser machen kann. Nach Abschluss der Analyse dieses Jahres gibt es zwei Dinge, die ich anders gemacht hätte. Leser, die eine ähnliche Strategie implementieren möchten, sollten diese beiden Punkte berücksichtigen:
1. Mehr Ereignisse im Zusammenhang mit der Ladezeit erfassen
Wir haben mehrere Ereignisse erfasst, die einem technischen Messwert entsprechen (z. B. HTMLImportsLoaded, WebComponentsReady usw.). Da jedoch ein Großteil der Ladung asynchron erfolgte, entsprach der Zeitpunkt, zu dem diese Ereignisse ausgelöst wurden, nicht unbedingt einem bestimmten Moment während des gesamten Ladevorgangs.
Das primäre ladebezogene Ereignis, das wir nicht erfasst haben, aber hätten, ist der Zeitpunkt, an dem der Splashscreen verschwand und der Nutzer den Seiteninhalt sehen konnte.
2. Analytics-Client-ID in IndexedDB speichern
Standardmäßig speichert analytics.js das Feld „client_id“ in den Cookies des Browsers. Leider können Service Worker-Scripts nicht auf Cookies zugreifen.
Das stellte ein Problem für uns dar, als wir versuchten, das Benachrichtigungs-Tracking zu implementieren. Wir wollten jedes Mal, wenn eine Benachrichtigung an einen Nutzer gesendet wurde, ein Ereignis vom Service Worker (über das Measurement Protocol) senden und dann den Erfolg der erneuten Interaktion mit dieser Benachrichtigung erfassen, wenn der Nutzer darauf geklickt und wieder zur App zurückgekehrt ist.
Wir konnten zwar den Erfolg von Benachrichtigungen im Allgemeinen über den utm_source
Kampagnenparameter erfassen, aber keine bestimmte erneute Interaktionssitzung einem bestimmten Nutzer zuordnen.
Wir hätten diese Einschränkung umgehen können, indem wir die Client-ID über IndexedDB in unserem Tracking-Code gespeichert hätten. Dann wäre dieser Wert für das Service Worker-Script zugänglich gewesen.
3. Service Worker den Online-/Offlinestatus melden lassen
Wenn Sie navigator.onLine
prüfen, können Sie feststellen, ob Ihr Browser eine Verbindung zum Router oder Local Area Network herstellen kann. Sie erfahren jedoch nicht unbedingt, ob der Nutzer eine echte Verbindung hat. Da unser Offline-Analyse-Serviceworker-Script fehlgeschlagene Treffer einfach noch einmal abspielte, ohne sie zu ändern oder als fehlgeschlagen zu kennzeichnen, wurden unsere Offlinenutzungszahlen wahrscheinlich zu niedrig erfasst.
In Zukunft sollten wir sowohl den Status von navigator.onLine
als auch prüfen, ob der Treffer aufgrund eines anfänglichen Netzwerkfehlers vom Service Worker noch einmal abgespielt wurde. So erhalten wir ein genaueres Bild der tatsächlichen Offlinenutzung.
Zusammenfassung
Diese Fallstudie hat gezeigt, dass die Verwendung von Service Workern die Ladeleistung der Google I/O-Web-App in einer Vielzahl von Browsern, Netzwerken und Geräten tatsächlich verbessert hat. Außerdem haben wir festgestellt, dass wir durch eine Verteilung der Ladedaten auf eine Vielzahl von Browsern, Netzwerken und Geräten viel mehr Einblick in die Verarbeitung von realen Szenarien durch diese Technologie erhalten und Leistungsmerkmale entdecken, die wir möglicherweise nicht erwartet haben.
Hier sind einige der wichtigsten Erkenntnisse aus der IOWA-Studie:
- Im Durchschnitt wurden Seiten, die von einem Service Worker gesteuert wurden, deutlich schneller geladen als Seiten ohne Service Worker, sowohl bei neuen als auch bei wiederkehrenden Besuchern.
- Besuche von Seiten, die von einem Service Worker gesteuert werden, wurden für viele Nutzer fast sofort geladen.
- Inaktive Service Worker benötigten beim Starten etwas Zeit. Ein inaktiver Service Worker schnitt jedoch immer noch besser ab als gar kein Service Worker.
- Die Startzeit für einen inaktiven Dienst-Worker war auf Mobilgeräten länger als auf dem Computer.
Die Leistungssteigerungen, die in einer bestimmten Anwendung beobachtet wurden, sind zwar im Allgemeinen nützlich, um sie der größeren Entwicklergemeinschaft zu melden, aber es ist wichtig zu bedenken, dass diese Ergebnisse spezifisch für die Art der Website von IOWA (eine Veranstaltungswebsite) und die Art der Zielgruppe von IOWA (vorwiegend Entwickler) sind.
Wenn Sie einen Dienst-Worker in Ihrer Anwendung implementieren, ist es wichtig, dass Sie Ihre eigene Analysestrategie implementieren, damit Sie Ihre eigene Leistung bewerten und zukünftige Rückgänge verhindern können. Wenn ja, teilen Sie uns Ihre Ergebnisse 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 HTTP-Cache zu vergleichen. Da wir IOWA für Service Worker optimiert haben, haben wir nicht viel Zeit für die Optimierung für den HTTP-Cache aufgewendet. Andernfalls wären die Ergebnisse wahrscheinlich anders ausgefallen. Weitere Informationen zum Optimieren Ihrer Website für den HTTP-Cache finden Sie unter Inhalte effizient optimieren.
- Je nachdem, wie die Stile und Inhalte Ihrer Website geladen werden, kann es sein, dass der Browser Inhalte anzeigen kann, bevor sie verfügbar sind. In solchen Fällen entspricht
firstpaint
möglicherweise einem leeren weißen Bildschirm. Wenn Siefirstpaint
verwenden, muss es einem sinnvollen Punkt beim Laden der Ressourcen Ihrer Website entsprechen. - Technisch gesehen könnten wir einen Timing-Hit (standardmäßig keine Interaktion) senden, um diese Informationen zu erfassen, anstatt ein Ereignis. Zeitmesswerte wurden in Google Analytics speziell zum Erfassen solcher Lademesswerte hinzugefügt. Bei der Verarbeitung werden sie jedoch stark beprobt und ihre Werte können nicht in Segmenten verwendet werden. Angesichts dieser aktuellen Einschränkungen sind Ereignisse ohne Interaktion weiterhin besser geeignet.
- Weitere Informationen dazu, welchen Umfang Sie einer benutzerdefinierten Dimension in Google Analytics zuweisen sollten, finden Sie in der Analytics-Hilfe im Abschnitt Benutzerdefinierte Dimension. 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.
- Das gilt nicht für Ressourcen, die nach dem Ladeereignis verzögert geladen werden.