Auswirkungen von Service Workern auf die Leistung in der Praxis messen

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 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 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 erfasst 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 durch den Service Worker leistungsfähiger als die bestehenden 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.

Durchschn. 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. 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 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. Aus diesem Grund ist es viel sinnvoller, zu verfolgen, wie lange es dauert, bis der Ladebildschirm erscheint, um die wahrgenommene Lastleistung zu messen. Wir haben den Messwert Zeit bis zur ersten Darstellung ausgewählt, um diesen Wert zu erhalten.

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 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 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 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.

Zeit bis zum First Paint erfassen

Einige Browser erfassen die genaue Zeit, zu der das erste Pixel auf den Bildschirm gezeichnet wird, und stellen diese Zeit den 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 vergangen ist, seit der Nutzer die Seite angefordert hat, bis 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 ein Nutzer die Ladegeschwindigkeit Ihrer Website wahrnimmt. 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, 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 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 den Status des Service Workers erfassen, da wir sonst die ersten Malzeiten einer von einem Service Worker gesteuerten Seite nicht mit denen 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. 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';
  }
}

Ü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 anhand von Nutzer-, Sitzungs- oder Interaktionsattributen in Gruppen zu unterteilen. 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, erfolgten fast 85% aller Seitenaufrufe für IOWA über Browser, die Service Worker unterstützen.

Das Ergebnis: Beantwortung unserer 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 Durchschn. 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 gesamten Ladezeit 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 er zurückkehrt. 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, 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 die Seiten für mobile Nutzer mit einem Service Worker im Durchschnitt schneller geladen wurden als für neue Desktop-Nutzer.

„…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 sich ein wiederkehrender Besucher, dessen Browser den Service Worker unterstützt, irgendwann 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 treten relativ selten auf. Das sehen wir in den Daten an den Werten für Beispiel für Seitenladezeit in der vierten Spalte. Beachten Sie, dass die mittleren Zeilen eine viel kleinere Stichprobe als die anderen beiden haben.

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 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.

„...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 uns die Daten genauer ansehen. 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 bestimmten Nutzerbereich aufschlüsseln, müssen wir uns eine Verteilung von firstpaint-mal ansehen.

Verteilung eines Messwerts in Google Analytics abrufen

Um die Verteilung der firstpaint-mal-Werte zu erhalten, benötigen wir Zugriff auf die einzelnen Ergebnisse für jedes Ereignis. Leider ist das in 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 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, 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:

  • 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.
  • 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. 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:

Verteilung der Zeit bis zur ersten Darstellung auf dem Computer (unterstützt)

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.

Verteilung der Zeit bis zur ersten Darstellung auf dem Computer (kontrolliert)

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…“

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 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.

Verteilung der Zeit bis zur ersten Darstellung auf dem Computer

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 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 die Ausdehnung dieser Verteilung. Bei einigen Nutzern trat beim Starten des Service Worker-Threads eine Verzögerung auf.

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:

Verteilung der Zeit bis zur ersten Darstellung auf Mobilgeräten

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 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

Das Erstellen dieser Verteilungsvisualisierungen war etwas zeitaufwendiger 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.

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 wird das nachträgliche Senden von Interaktionsdaten unterstützt. Dazu wird über den Parameter qt ein Zeitversatz angegeben.

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 dem Erhalt von Push-Benachrichtigungen zustimmen. 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 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 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 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 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
    });
  });
});

Etwa 10% der Nutzer, die ein App-Installationsbanner gesehen haben, entschieden sich dafür, es zu ihrem Startbildschirm hinzuzufügen.

Mögliche Tracking-Verbesserungen (fürs nächste 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 Analyse dieses Jahres gibt es zwei Dinge, die wir gerne anders gemacht hätten. 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.

Dies stellte ein Problem für uns dar, als wir versucht haben, die Benachrichtigungsverfolgung 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. Der Service Worker kann den Online-/Offlinestatus melden.

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, wurde unsere Offlinenutzung 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. Es hat sich auch gezeigt, dass man bei einer Verteilung der Lastdaten für eine Vielzahl von Browsern, Netzwerken und Geräten viel mehr Informationen dazu erhält, wie diese Technologie reale Szenarien handhabt, und Leistungsmerkmale zu entdecken, die Sie möglicherweise nicht erwartet hätten.

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 etwas Zeit, um gestartet zu werden. 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 beachten, 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 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 uns Ihre Ergebnisse 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 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.
  2. 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 Sie firstpaint verwenden, muss es einem sinnvollen Punkt beim Laden der Ressourcen Ihrer Website entsprechen.
  3. 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 besser geeignet.
  4. 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.
  5. Das gilt nicht für Ressourcen, die nach dem Ladeereignis verzögert geladen werden.