Auswirkungen von Service Workern auf die Leistung in der Praxis messen

Einer der bedeutendsten Vorteile von Service Workern (mindestens aus Sicht der Leistung) 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 deutlich schneller geladen werden. Aber wie sehen diese Vorteile für echte Nutzer aus? Und wie lässt sich das messen?

Die Google I/O-Web-App (kurz IOWA) ist eine progressive Web-App, die die meisten neuen Funktionen von Service Workern nutzte, um ihren Nutzern ein umfassendes, app-ähnliches Erlebnis zu bieten. Außerdem wurden mithilfe von Google Analytics wichtige Leistungsdaten und Nutzungsmuster der großen und vielfältigen Nutzergruppe erfasst.

In dieser Fallstudie wird untersucht, wie IOWA mithilfe von Google Analytics wichtige Leistungsfragen beantwortet und über die tatsächlichen Auswirkungen von Servicemitarbeitern berichtet.

Beginnen wir mit den Fragen,

Jedes Mal, wenn Sie Analysen in einer Website oder Anwendung implementieren, ist es wichtig, zunächst die Fragen zu identifizieren, die Sie anhand der erfassten Daten zu beantworten versuchen.

Wir hatten zwar mehrere Fragen, die wir beantworten wollten. Konzentrieren wir uns für diese Fallstudie jedoch auf zwei der interessanteren.

1. Ist das Service Worker-Caching leistungsfähiger als die bestehenden HTTP-Caching-Mechanismen, die in allen Browsern verfügbar sind?

Wir erwarten bereits, dass Seiten bei wiederkehrenden Besuchern schneller als bei neuen Besuchern geladen werden, da Browser Anfragen im Cache speichern und bei wiederholten Besuchen sofort bereitstellen können.

Service Worker bieten alternative Caching-Funktionen, mit denen Entwickler genau steuern können, was und wie das Caching durchgeführt wird. In IOWA haben wir unsere Service Worker-Implementierung so optimiert, dass jedes Asset im Cache gespeichert wird, sodass wiederkehrende Besucher die App vollständig offline nutzen können.

Aber wäre dieser Aufwand besser als der, was der Browser 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, als ob die Website geladen wird, unabhängig von den tatsächlichen Ladezeiten, die anhand herkömmlicher Seitenlademesswerte gemessen werden?

Es ist offensichtlich nicht einfach, Fragen dazu zu beantworten, wie sich eine Erfahrung anfühlt, und keine Metrik kann diese subjektive Stimmung perfekt widerspiegeln. Allerdings gibt es definitiv einige Messwerte, die besser sind als andere, daher ist es wichtig, die richtigen 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 die durchschnittliche Seitenladezeit zur Verfügung.

Durchschn. Seitenladezeit ist ein guter Messwert zur Beantwortung der ersten Frage. Bei der zweiten Frage ist er jedoch nicht besonders gut geeignet. Zum einen entspricht das load-Ereignis nicht unbedingt dem Moment, in dem der Nutzer tatsächlich mit der App interagieren kann. Außerdem haben zwei Apps mit genau derselben Ladezeit möglicherweise das Gefühl, dass sie viel unterschiedlich geladen werden. Eine Website mit einem Ladebildschirm oder einer Ladeanzeige fühlt sich beispielsweise viel schneller an als eine Website, auf der mehrere Sekunden lang nur eine leere Seite angezeigt wird.

Bei IOWA haben wir eine Countdown-Animation für den Ladebildschirm gezeigt, die meiner Meinung nach sehr erfolgreich war, um den Nutzer zu unterhalten, während der Rest der App im Hintergrund geladen wurde. Daher ist es viel sinnvoller, zu verfolgen, wie lange es dauert, bis der Begrüßungsbildschirm erscheint, um die wahrgenommene Lastleistung zu messen. Um diesen Wert zu erhalten, haben wir den Messwert Zeit für Erstmalerei ausgewählt.

Nachdem wir uns entschieden hatten, welche Fragen wir beantworten wollten, und welche Kennzahlen für die Beantwortung nützlich sein könnten, war es an der Zeit, Google Analytics zu implementieren und mit der Messung zu beginnen.

Die Analytics-Implementierung

Wenn Sie Google Analytics bereits verwendet haben, sind Sie wahrscheinlich schon 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>

Die erste Zeile im Code oben initialisiert eine globale ga()-Funktion (falls noch nicht vorhanden) und die letzte Zeile lädt die analytics.js-Bibliothek asynchron herunter.

Der mittlere Teil enthält diese beiden Zeilen:

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

Mit diesen beiden Befehlen wird erfasst, 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 weitere Dinge nachverfolgen:

  • Die verstrichene Zeit zwischen dem ersten Laden der Seite und dem Erscheinen der Pixel auf dem Bildschirm.
  • Gibt an, ob ein Service Worker die Seite steuert. Anhand dieser Informationen konnten wir unsere Berichte segmentieren, um die Ergebnisse mit und ohne Service Worker zu vergleichen.

Zeit bis zum ersten Malen einfangen

Einige Browser zeichnen genau den Zeitpunkt auf, zu dem das erste Pixel auf dem Bildschirm dargestellt wird, und stellen diese Zeit Entwicklern zur Verfügung. Wenn wir diesen Wert mit dem Wert navigationStart vergleichen, der über die Navigation Timing API angezeigt wird, lässt sich sehr genau erfassen, wie viel Zeit zwischen der ersten Anforderung der Seite durch den Nutzer und dem ersten Aufruf der Seite verstrichen ist.

Wie bereits erwähnt, ist die Zeit bis zum ersten Mal ein wichtiger Messwert, da dies der erste Punkt ist, an dem Nutzer die Ladegeschwindigkeit Ihrer Website erleben. Es ist der erste Eindruck, den Nutzer erhalten, und ein guter erster Eindruck kann sich positiv auf die Nutzererfahrung auswirken.2

Um den First Paint-Wert in Browsern zu erhalten, in denen er verfügbar ist, haben wir das Dienstprogramm 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 nun eine weitere Funktion schreiben, die ein Ereignis ohne Interaktion mit der Zeit für First Paint als Wert sendet: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 diese beiden Funktionen geschrieben wurden, sieht unser Tracking-Code wie folgt 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 obige Code ausgeführt wird, wurden möglicherweise bereits Pixel auf dem Bildschirm dargestellt. Damit dieser Code immer nach dem ersten Paint-Vorgang ausgeführt wird, haben wir den Aufruf von sendTimeToFirstPaint() bis nach dem load-Ereignis verschoben. Wir haben uns entschieden, das Senden aller Analysedaten erst 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();
});

Der Code oben meldet firstpaint-mal an Google Analytics, aber das ist nur die halbe Miete. Der Service Worker-Status muss dennoch erfasst werden. Andernfalls könnten wir die First Paint-Zeiten einer von einem Service Worker kontrollierten Seite nicht mit einer nicht kontrollierten Seite vergleichen.

Service Worker-Status ermitteln

Um den aktuellen Status des Service Workers zu ermitteln, haben wir eine Dienstprogrammfunktion erstellt, die einen von drei Werten zurückgibt:

  • kontrolliert: Die Seite wird von einem Service Worker gesteuert. Im Fall einer IOWA bedeutet das außerdem, dass alle Assets im Cache gespeichert wurden und die Seite offline funktioniert.
  • supported (unterstützt): Der Browser unterstützt den Service Worker, steuert die Seite jedoch noch nicht. Dies ist der erwartete Status für erstmalige Besucher.
  • unsupported (nicht unterstützt): Der Browser des Nutzers unterstützt keinen Service Worker.
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. Im nächsten Schritt verknüpfen wir diesen Status mit den Daten, die wir an Google Analytics gesendet haben.

Tracking benutzerdefinierter Daten mit benutzerdefinierten Dimensionen

Standardmäßig bietet Google Analytics zahlreiche Möglichkeiten, den gesamten Traffic basierend auf den Attributen des Nutzers, der Sitzung oder der Interaktion in Gruppen zu unterteilen. Diese Attribute werden als Dimensionen bezeichnet. Zu den gängigen Dimensionen für Webentwickler gehören z. B. Browser, Betriebssystem oder Gerätekategorie.

Der Service Worker-Status ist keine Dimension, die in Google Analytics standardmäßig zur Verfügung gestellt wird. Sie können in Google Analytics jedoch Ihre eigenen benutzerdefinierten Dimensionen erstellen und beliebig definieren.

Für IOWA haben wir eine benutzerdefinierte Dimension namens Service Worker Status erstellt und ihren Umfang auf hit (pro Interaktion) festgelegt.4 Jede benutzerdefinierte Dimension, die Sie in Google Analytics erstellen, erhält einen eindeutigen Index innerhalb dieser Property. Im Tracking-Code können Sie über ihren Index auf diese Dimension verweisen. Wenn der Index der soeben erstellten Dimension beispielsweise 1 ist, können wir die Logik so aktualisieren, dass das firstpaint-Ereignis den Service Worker-Status enthält:

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, verknüpft jedoch nur den Status des Service Workers mit diesem bestimmten Ereignis. Da der Service Worker-Status sehr nützlich für jede Interaktion ist, sollten Sie ihn in alle Daten aufnehmen, die an Google Analytics gesendet werden.

Damit diese Informationen in alle Treffer (z. B. Seitenaufrufe und Ereignisse) aufgenommen werden, wird der Wert der benutzerdefinierten Dimension auf dem tracker-Objekt festgelegt, bevor Daten an Google Analytics gesendet werden.

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

Nachdem dieser Wert festgelegt wurde, wird er mit allen nachfolgenden Treffern für den aktuellen Seitenaufbau gesendet. Wenn der Nutzer die Seite später noch einmal lädt, wird wahrscheinlich von der Funktion getServiceWorkerStatus() ein neuer Wert zurückgegeben, der auf dem Tracker-Objekt festgelegt wird.

Ein kurzer Hinweis zur besseren Lesbarkeit von Code: Da andere Nutzer, die sich diesen Code ansehen, möglicherweise nicht wissen, worauf sich dimension1 bezieht, ist es immer 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 mit jedem Treffer für Berichte zu beliebigen Messwerten verwenden.

Sie sehen, dass fast 85% aller Seitenaufrufe für IOWA von Browsern stammen, die Servicemitarbeiter unterstützen.

Das Ergebnis: Antworten auf unsere Fragen

Nachdem wir mit der Erfassung von Daten begonnen hatten, um unsere Fragen zu beantworten, konnten wir einen Bericht mit diesen Daten erstellen, um die Ergebnisse zu sehen. Hinweis: Alle hier gezeigten Google Analytics-Daten stellen den tatsächlichen Web-Traffic auf der IOWA-Website vom 16. bis 22. Mai 2016 dar.

Die erste Frage war: Ist das Service Worker-Caching 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, in dem der Messwert Durchschn. Seitenladezeiten für verschiedene Dimensionen untersucht wurde. Dieser Messwert eignet sich gut zur Beantwortung dieser Frage, da das Ereignis load erst ausgelöst wird, nachdem alle anfänglichen Ressourcen heruntergeladen wurden. Daher entspricht sie direkt der Gesamtladezeit für alle kritischen Ressourcen der Website.5

Wir wählten folgende Dimensionen aus:

  • Die benutzerdefinierte Dimension Service Worker-Status
  • Nutzertyp: Gibt an, ob es sich um den ersten Besuch der Website des Nutzers handelt oder ob er zurückkehrt. Hinweis: Ein neuer Besucher hat keine Ressourcen im Cache, ein wiederkehrender Besucher hingegen schon.
  • Gerätekategorie: Damit können die Ergebnisse für Mobilgeräte und Computer verglichen werden.

Um die Möglichkeit zu vermeiden, dass nicht auf Service-Worker bezogene Faktoren unsere Ergebnisse der Ladezeit verzerren, haben wir unsere Abfrage auf Browser beschränkt, die Service Worker unterstützen.

Sie sehen, dass Besuche unserer App bei Steuerung durch einen Service Worker viel schneller geladen werden als nicht kontrollierte Besuche, selbst solche von wiederkehrenden Nutzern, bei denen wahrscheinlich der Großteil der Seitenressourcen im Cache gespeichert war. Interessant ist auch, dass Besucher auf Mobilgeräten mit Service Worker im Durchschnitt schneller laden als neue Desktop-Nutzer.

„...die durch einen Service Worker gesteuerten Besuche in unserer App 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 passieren kann, dass ein wiederkehrender Besucher, dessen Browser Service Worker unterstützt, sich jemals in einem nicht kontrollierten Zustand befindet. Es gibt einige mögliche Erklärungen dafür:

  • 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 Fälle treten relativ selten auf. Das können wir in den Daten an den Werten für Seitenladebeispiel in der vierten Spalte sehen. Beachten Sie, dass die mittlere Stichprobe viel kleiner ist als die anderen beiden Zeilen.

Unsere zweite Frage lautete: Welche Auswirkungen haben Service Worker auf das Laden der Website?

Zur Beantwortung dieser Frage haben wir einen weiteren benutzerdefinierten Bericht für den Messwert Durchschn. Ereigniswert erstellt und die Ergebnisse so gefiltert, dass sie nur unsere firstpaint-Ereignisse enthalten. Dazu wurden die Dimensionen Gerätekategorie und die benutzerdefinierte Dimension Service Worker-Status verwendet.

Anders als ich erwartet hatte, hatte der Service Worker auf der mobilen Website viel weniger Auswirkungen auf die Zeit bis zum ersten Malen als auf den gesamten Seitenaufbau.

„...die Servicemitarbeiter auf Mobilgeräten hatten wesentlich weniger Einfluss auf die Zeit bis zum ersten Malen als auf den gesamten Seitenaufbau.“

Um zu erfahren, warum das so ist, müssen wir die Daten genauer untersuchen. Durchschnittswerte können für allgemeine Übersichten und einen groben Überblick verwendet werden. Um jedoch ein Gefühl dafür zu bekommen, wie sich diese Zahlen auf eine bestimmte Nutzergruppe zusammensetzen, müssen wir uns die Verteilung der firstpaint-Werte genauer 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 einfach.

Mit Google Analytics können Sie einen Bericht nach beliebigen Dimensionen aufschlüsseln, die Aufschlüsselung eines Berichts nach Messwerten ist jedoch nicht möglich. Das heißt nicht, dass es unmöglich ist. Es bedeutet nur, dass wir unsere Implementierung etwas stärker 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-mal) als benutzerdefinierte Dimension für das Ereignis festlegen. Dazu haben wir eine weitere benutzerdefinierte Dimension namens Messwert erstellt und die firstpaint-Tracking-Logik folgendermaßen 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);
  }
}

Auf der Weboberfläche von Google Analytics ist derzeit keine Visualisierung der Verteilung beliebiger Messwerte möglich. Mithilfe der Google Analytics Core Reporting API und der Google Charts-Bibliothek können wir jedoch die Rohdaten abfragen und dann selbst ein Histogramm erstellen.

Die folgende API-Anfragekonfiguration wurde beispielsweise verwendet, um eine Verteilung von firstpaint-Werten auf einem Desktop mit einem nicht kontrollierten Service Worker 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 mit Werten zurück, die wie folgt aussehen. Hinweis: Dies sind nur die ersten fünf Ergebnisse. Die Ergebnisse werden vom kleinsten zum größten 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

Im einfachen Englisch bedeutet dies Folgendes:

  • Es gab 3 Ereignisse, bei denen der Wert von firstpaint 4 ms betrug
  • Es gab 2 Ereignisse, bei denen der Wert von firstpaint 5 ms betrug
  • Es gab 10 Ereignisse, bei denen der Wert von firstpaint 6 ms betrug
  • Es gab 8 Ereignisse, bei denen der Wert von firstpaint 7 ms betrug
  • Es gab 10 Ereignisse, bei denen firstpaint value 8 ms betrug
  • und so weiter

Aus diesen Ergebnissen können wir den firstpaint-Wert für jedes einzelne Ereignis extrapolieren und ein Histogramm der Verteilung erstellen. Das haben wir für jede Abfrage gemacht, die wir ausgeführt haben.

So sah die Verteilung auf dem Desktop mit einem nicht kontrollierten (aber unterstützten) Service Worker aus:

Verteilung der Zeit bis zum ersten Mal auf dem Computer (unterstützt)

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 Ladezeiten recht typisch. Im Gegensatz dazu ist das Histogramm unten zu sehen, in dem die Verteilung von First Paint-Ereignissen für Besuche dargestellt wird, bei denen die Seite von einem Service Worker gesteuert wurde.

Verteilung der Zeit bis zum ersten Mal auf dem Computer (kontrolliert)

Beachten Sie, dass bei vielen Besuchern bei der Steuerung der Seite durch ein Service Worker der erste Paint mit einem Medianwert von 583 ms nahezu sofort angezeigt wurde.

"...als ein Service Worker die Seite steuerte, erlebten viele Besucher beinahe sofortigen Erstanstrich ..."

Das nächste Diagramm zeigt eine zusammengeführte Ansicht der beiden Verteilungen, um einen besseren Vergleich der beiden Verteilungen zu erhalten. Das Histogramm mit den nicht kontrollierten Service Worker-Besuchen wird über das Histogramm gelegt, das kontrollierte Besuche zeigt, und beide sind über einem Histogramm gelegt, das beide kombiniert zeigt.

Die Verteilung der Zeit bis zum ersten Mal (Time to First Paint) auf dem Computer

Interessant an diesen Ergebnissen war, dass die Verteilung mit einem kontrollierten Service Worker nach dem ersten Anstieg immer noch eine glockenförmige Kurve aufwies. Ich hatte anfänglich mit einem starken Anstieg und einem allmählichen Nachlassen gerechnet. Mit einem zweiten Spitzenwert in der Kurve hatte ich nicht gerechnet.

Als ich untersuchte, was die Ursache sein könnte, habe ich herausgefunden, dass ein Service Worker eine Seite zwar steuern kann, der zugehörige Thread aber inaktiv sein kann. Der Browser tut dies, um Ressourcen zu sparen – natürlich müssen nicht alle Service Worker für jede von Ihnen besuchte Website sofort aktiv und bereit sein. Dies erklärt den Extremwert der Verteilung. Bei einigen Nutzern trat beim Start des Service Worker-Threads eine Verzögerung auf.

Wie Sie an der Verteilung sehen können, übermittelten Browser mit Service Worker Inhalte trotz dieser anfänglichen Verzögerung schneller als Browser, die das Netzwerk durchlaufen.

So sah das Ganze auf Mobilgeräten aus:

Verteilung der Zeit bis zum ersten Mal (Time to First Paint) auf Mobilgeräten

Zwar gab es immer noch eine deutliche Zunahme der beinahe sofortigen First Paint-Zeiten, aber der Ausläufer war ziemlich viel 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. Es erklärt auch, warum der Unterschied zwischen der durchschnittlichen firstpaint-Zeit nicht so groß war wie erwartet (siehe oben).

„Auf Mobilgeräten dauert das Starten eines inaktiven Service Worker-Threads länger als auf dem Desktop.“

Hier ist die Aufschlüsselung dieser Abweichungen der Medianwert für die Erstmalung auf Mobilgeräten und Computern 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 2006

Das Erstellen dieser Verteilungsvisualisierungen kostete zwar etwas mehr Zeit und Aufwand als die Erstellung eines benutzerdefinierten Berichts in Google Analytics, aber sie vermitteln uns ein viel besseres Gefühl dafür, wie Service Worker die Leistung unserer Website beeinflussen als der Durchschnitt allein.

Andere Auswirkungen von Service Workers

Neben der Leistung wirken sich Service Worker auch auf andere Weise auf die Nutzererfahrung aus, die mit Google Analytics gemessen werden können.

Offlinezugriff

Service Worker ermöglichen es Nutzern, auch offline mit Ihrer Website zu interagieren, und während eine Art Offline-Support wahrscheinlich für jede progressive Web-App von entscheidender Bedeutung ist, hängt die Entscheidung, wie wichtig diese in Ihrem Fall ist, vor allem davon ab, wie intensiv die Offline-Nutzung ist. Aber wie können wir das messen?

Für das Senden von Daten an Google Analytics ist eine Internetverbindung erforderlich. Sie müssen jedoch nicht genau zum Zeitpunkt der Interaktion gesendet werden. In Google Analytics können Interaktionsdaten auch nachträglich gesendet werden. Dazu wird über den Parameter qt ein Zeitversatz angegeben.

Seit zwei Jahren verwendet IOWA ein Service Worker-Skript, das fehlgeschlagene Treffer an Google Analytics erkennt, wenn der Nutzer offline ist, und diese später mit dem Parameter qt wiedergibt.

Um zu erfassen, ob der Nutzer online oder offline war, haben wir die benutzerdefinierte Dimension Online erstellt und auf den Wert navigator.onLine gesetzt. Dann wurde auf die Ereignisse online und offline gewartet und die Dimension entsprechend angepasst.

Um ein Gefühl dafür zu bekommen, wie häufig ein Nutzer während der Verwendung von IOWA offline war, haben wir ein Segment erstellt, das auf Nutzer mit mindestens einer Offlineinteraktion ausgerichtet war. 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 benachrichtigt, wenn eine Sitzung in ihrem Zeitplan beginnen sollte.

Wie bei jeder Art von Benachrichtigungen ist es wichtig, ein Gleichgewicht zwischen Mehrwert für den Nutzer und störender Nutzer zu finden. Um besser zu verstehen, was passiert, ist es wichtig zu verfolgen, ob Nutzer sich für den Erhalt dieser Benachrichtigungen angemeldet haben, ob sie mit ihnen interagieren, wenn sie dies tun, und ob Nutzer, die zuvor die Verwendung aktiviert haben, ihre Einstellungen ändern oder widersprechen.

In IOWA haben wir nur Benachrichtigungen gesendet, die sich auf den personalisierten Zeitplan des Nutzers bezogen, etwas, das nur angemeldete Nutzer erstellen konnten. Dadurch wird die Gruppe der Nutzer, die Benachrichtigungen erhalten konnten, auf angemeldete Nutzer beschränkt, die über die benutzerdefinierte Dimension Angemeldet erfasst wurden und deren Browser Push-Benachrichtigungen unterstützt haben. Dies wird über die benutzerdefinierte Dimension Benachrichtigungsberechtigung erfasst.

Der folgende Bericht basiert auf dem Messwert Nutzer und unserer benutzerdefinierten Dimension „Benachrichtigungsberechtigung“. Diese sind nach Nutzern segmentiert, die sich zu einem bestimmten Zeitpunkt angemeldet haben und deren Browser Push-Benachrichtigungen unterstützen.

Es ist gut zu sehen, dass mehr als die Hälfte unserer angemeldeten Nutzer Push-Benachrichtigungen erhalten.

App-Installationsbanner

Wenn eine Fortschritts-Web-App die Kriterien erfüllt und häufig von einem Nutzer verwendet wird, wird diesem Nutzer möglicherweise ein App-Installationsbanner angezeigt, in dem er aufgefordert wird, die App zu seinem Startbildschirm hinzuzufügen.

In IOWA haben wir mit dem folgenden Code erfasst, wie oft diese Aufforderungen dem Nutzer 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 sahen, fügten es zu ihrem Startbildschirm hinzu.

Mögliche Verbesserungen beim Tracking (für das nächste Mal)

Die Analytics-Daten, die wir in diesem Jahr von IOWA gesammelt haben, waren von unschätzbarem Wert. Im Rückblick ergeben sich aber immer wieder kleine Lücken und Chancen, sich für das nächste Mal zu verbessern. Nach Abschluss der diesjährigen Analyse hätten wir diese zwei Dinge gerne anders gemacht, die Leser, die eine ähnliche Strategie umsetzen möchten, eventuell berücksichtigen würden:

1. Weitere Ereignisse im Zusammenhang mit dem Laden erfassen

Wir haben mehrere Ereignisse erfasst, die einem technischen Messwert entsprechen (z.B. HTMLImportsLoaded oder WebComponentsReady). Da ein großer Teil des Ladevorgangs jedoch asynchron erfolgte, entsprach der Zeitpunkt, an dem diese Ereignisse ausgelöst wurden, nicht unbedingt einem bestimmten Zeitpunkt im gesamten Ladevorgang.

Das primäre Ereignis in Zusammenhang mit dem Laden, das wir nicht erfasst haben (wollen wir uns jedoch wünschen) ist die Stelle, an der der Ladebildschirm verschwunden ist 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. Leider können Service Worker-Skripts nicht auf Cookies zugreifen.

Dies stellte ein Problem für uns dar, als wir versuchten, die Benachrichtigungsverfolgung zu implementieren. Wir wollten jedes Mal, wenn eine Benachrichtigung an einen Nutzer gesendet wird, ein Ereignis vom Service Worker (über das Measurement Protocol) senden und den Erfolg der erneuten Interaktion mit dieser Benachrichtigung erfassen, wenn der Nutzer darauf klickte und zur App zurückkehrt.

Wir konnten den Erfolg von Benachrichtigungen allgemein über den Kampagnenparameter utm_source erfassen, aber keine bestimmte Sitzung für erneute Interaktionen einem bestimmten Nutzer zuordnen.

Um diese Einschränkung zu umgehen, hätten wir die Client-ID über IndexedDB in unserem Tracking-Code speichern können. Dieser Wert wäre dann für das Service Worker-Skript zugänglich.

3. Online-/Offlinestatus durch Service Worker melden

Durch die Überprüfung von navigator.onLine erfährst du, ob dein Browser eine Verbindung zum Router oder Local Area Network herstellen kann, aber nicht, ob der Nutzer eine echte Verbindung hat. Und da unser Service Worker-Skript für die Offlineanalyse fehlgeschlagene Treffer einfach wiedergibt (ohne sie zu ändern oder als fehlgeschlagen zu kennzeichnen), haben wir die Offlinenutzung wahrscheinlich zu wenig erfasst.

Zukünftig sollten wir sowohl den Status von navigator.onLine als auch feststellen, ob der Treffer vom Service Worker nach einem ersten Netzwerkfehler noch einmal wiedergegeben wurde. Dadurch erhalten wir ein genaueres Bild der tatsächlichen Offlinenutzung.

Zusammenfassung

Diese Fallstudie hat gezeigt, dass durch die Verwendung eines Service Workers die Lastleistung der Google I/O-Webanwendung in einer Vielzahl von Browsern, Netzwerken und Geräten verbessert wurde. Außerdem hat sich gezeigt, dass Sie bei der Verteilung der Lastdaten über eine Vielzahl von Browsern, Netzwerken und Geräten viel mehr Informationen dazu erhalten, wie diese Technologie mit realen Szenarien umgeht, und Leistungsmerkmale entdecken, die Sie möglicherweise nicht erwartet hatten.

Hier sind einige der wichtigsten Erkenntnisse, die wir aus der IOWA-Studie gewonnen haben:

  • Wenn ein Service Worker die Seite steuerte, wurden die Seiten im Durchschnitt etwas schneller geladen als ohne Service Worker. Dies gilt sowohl für neue als auch für wiederkehrende Besucher.
  • Besuche von Seiten, die von einem Service Worker gesteuert werden, wurden bei vielen Nutzern nahezu sofort geladen.
  • Der Start von Service Workern dauerte eine Weile, wenn sie inaktiv waren. Ein inaktiver Service Worker hat jedoch immer noch eine bessere Leistung als kein Service Worker.
  • Bei einem inaktiven Service Worker dauerte die Startzeit auf Mobilgeräten länger als auf dem Desktop.

Auch wenn die in einer bestimmten Anwendung beobachteten Leistungssteigerungen im Allgemeinen nützlich sind, um der größeren Entwickler-Community Bericht zu geben, sollten Sie bedenken, dass diese Ergebnisse spezifisch für die Art der Website sind, die IOWA ist (eine Veranstaltungswebsite) und die Art der Zielgruppe, die IOWA hat (hauptsächlich Entwickler).

Wenn Sie einen Service Worker in Ihrer Anwendung implementieren, ist es wichtig, dass Sie eine eigene Messstrategie implementieren, damit Sie Ihre eigene Leistung bewerten und zukünftige Regressionen vermeiden können. Wenn ja, teile deine Ergebnisse bitte mit, damit alle davon profitieren können!

Fußnoten

  1. Es ist nicht ganz fair, die Leistung unserer Service Worker-Cache-Implementierung mit der Leistung unserer Website mit dem HTTP-Cache allein zu vergleichen. Da wir IOWA für Service Worker optimieren, haben wir nicht viel Zeit für die Optimierung für den HTTP-Cache aufgewendet. Andernfalls wären die Ergebnisse wahrscheinlich anders gewesen. Weitere Informationen zur Optimierung Ihrer Website für den HTTP-Cache finden Sie unter Inhalte effizient optimieren.
  2. Je nachdem, wie Ihre Website ihre Stile und Inhalte lädt, ist es möglich, dass der Browser malt, bevor Inhalte oder Stile verfügbar sind. In solchen Fällen kann firstpaint einem leeren weißen Bildschirm entsprechen. Wenn du firstpaint verwendest, ist es wichtig, dass es beim Laden der Ressourcen deiner Website einem aussagekräftigen Punkt entspricht.
  3. Technisch gesehen könnte ein zeitbezogener Treffer (standardmäßig keine Interaktion) gesendet werden, um diese Informationen anstelle eines Ereignisses zu erfassen. Tatsächlich wurden in Google Analytics Timing-Treffer speziell zum Nachverfolgen von Lastmesswerten wie diesem hinzugefügt. Timing-Treffer werden jedoch zur Verarbeitungszeit umfassend erhoben und ihre Werte können nicht in Segmenten verwendet werden. Angesichts dieser aktuellen Einschränkungen sind Ereignisse ohne Interaktion weiterhin besser geeignet.
  4. Weitere Informationen dazu, welchen Umfang Sie in Google Analytics für eine benutzerdefinierte Dimension verwenden sollten, finden Sie in der Analytics-Hilfe unter 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.
  5. Ressourcen, die nach dem Ladenereignis verzögert geladen werden, werden hier nicht berücksichtigt.