L'un des avantages les plus importants des service workers (du moins d'un point de vue des performances) est leur capacité à contrôler de manière proactive le mise en cache des composants. Une application Web capable de mettre en cache toutes ses ressources nécessaires devrait se charger beaucoup plus rapidement pour les visiteurs réguliers. Mais à quoi ressemblent ces gains pour les utilisateurs réels ? Comment pouvez-vous mesurer cela ?
L'application Web Google I/O (IOWA, pour "Google I/O Web App") est une application Web progressive qui exploite la plupart des nouvelles fonctionnalités offertes par les service workers pour offrir une expérience riche, semblable à une application, à ses utilisateurs. Elle a également utilisé Google Analytics pour collecter des données de performances et des tendances d'utilisation clés auprès de son audience d'utilisateurs large et diversifiée.
Cette étude de cas explique comment IOWA a utilisé Google Analytics pour répondre à des questions clés sur les performances et évaluer l'impact réel des service workers.
En commençant par les questions
Chaque fois que vous implémentez des données analytiques sur un site Web ou dans une application, il est important de commencer par identifier les questions auxquelles vous essayez de répondre à partir des données que vous allez collecter.
Nous avions plusieurs questions à poser, mais pour les besoins de cette étude de cas, nous allons nous concentrer sur deux des plus intéressantes.
1. La mise en cache du service worker est-elle plus performante que les mécanismes de mise en cache HTTP existants disponibles dans tous les navigateurs ?
Nous nous attendons déjà à ce que les pages se chargent plus rapidement pour les visiteurs de retour que pour les nouveaux visiteurs, car les navigateurs peuvent mettre en cache les requêtes et les diffuser instantanément lors des visites répétées.
Les services workers proposent d'autres fonctionnalités de mise en cache qui permettent aux développeurs de contrôler précisément ce qui est mis en cache et comment. Dans IOWA, nous avons optimisé l'implémentation de notre service worker afin que chaque composant soit mis en cache, ce qui permet aux visiteurs réguliers d'utiliser l'application entièrement hors connexion.
Mais cet effort serait-il meilleur que ce que le navigateur fait déjà par défaut ? Si oui, dans quelle mesure ? 1
2. Quel est l'impact du service worker sur l'expérience de chargement du site ?
En d'autres termes, à quelle vitesse vous semble-t-il que le site se charge, quel que soit le temps de chargement réel mesuré par les métriques de chargement de page traditionnelles ?
Répondre à des questions sur le ressenti d'une expérience n'est évidemment pas une tâche facile, et aucune métrique ne peut représenter parfaitement un sentiment aussi subjectif. Cela dit, certaines métriques sont meilleures que d'autres. Il est donc important de choisir les bonnes.
Choisir la bonne métrique
Par défaut, Google Analytics suit les temps de chargement des pages (via l'API Navigation Timing) pour 1% des visiteurs d'un site. Il met ces données à disposition via des métriques telles que la durée moyenne de chargement des pages.
La métrique Temps de chargement moyen de la page est utile pour répondre à la première question, mais pas particulièrement pour répondre à la seconde. D'une part, l'événement load
ne correspond pas nécessairement au moment où l'utilisateur peut réellement interagir avec l'application. De plus, deux applications ayant exactement le même temps de chargement peuvent donner l'impression qu'elles se chargent de manière très différente. Par exemple, un site avec un écran de démarrage ou un indicateur de chargement semble probablement se charger beaucoup plus rapidement qu'un site qui affiche simplement une page vide pendant plusieurs secondes.
Dans IOWA, nous avons affiché une animation de compte à rebours sur l'écran de démarrage qui, à mon avis, a très bien servi à divertir l'utilisateur pendant que le reste de l'application se chargeait en arrière-plan. Par conséquent, il est beaucoup plus logique de suivre le temps d'affichage de l'écran de démarrage pour mesurer les performances de chargement perçues. Nous avons choisi la métrique Temps d'affichage de la première peinture pour obtenir cette valeur.
Une fois que nous avons décidé des questions auxquelles nous voulions répondre et identifié les métriques qui nous y aideraient, il était temps d'implémenter Google Analytics et de commencer à mesurer.
Implémentation des données analytiques
Si vous avez déjà utilisé Google Analytics, vous connaissez probablement l'extrait de code de suivi JavaScript recommandé. Elle se présente comme suit :
<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>
La première ligne du code ci-dessus initialise une fonction ga()
globale (si elle n'existe pas déjà), et la dernière ligne télécharge de manière asynchrone la bibliothèque analytics.js
.
La partie centrale contient les deux lignes suivantes:
ga('create', 'UA-XXXXX-Y', 'auto');
ga('send', 'pageview');
Ces deux commandes permettent de suivre les pages consultées par les utilisateurs qui accèdent à votre site, mais pas beaucoup plus. Si vous souhaitez suivre d'autres interactions utilisateur, vous devez le faire vous-même.
Pour IOWA, nous souhaitions suivre deux éléments supplémentaires:
- Temps écoulé entre le début du chargement de la page et l'affichage des pixels à l'écran.
- Indique si un service worker contrôle la page. Grâce à ces informations, nous pouvons segmenter nos rapports pour comparer les résultats avec et sans service worker.
Capturer le délai avant la première peinture
Certains navigateurs enregistrent l'heure exacte à laquelle le premier pixel est peint à l'écran et mettent cette heure à la disposition des développeurs. Cette valeur, comparée à la valeur navigationStart
exposée via l'API Navigation Timing, nous donne une estimation très précise du temps écoulé entre le moment où l'utilisateur a initialement demandé la page et celui où il a vu quelque chose pour la première fois.
Comme je l'ai déjà mentionné, le temps de première peinture est une métrique importante à mesurer, car c'est le premier point où un utilisateur ressent la vitesse de chargement de votre site. C'est la première impression que les utilisateurs ont de votre application. Une bonne première impression peut avoir un impact positif sur le reste de l'expérience utilisateur.2
Pour obtenir la première valeur de peinture dans les navigateurs qui l'exposent, nous avons créé la fonction utilitaire getTimeToFirstPaintIfSupported
:
function getTimeToFirstPaintIfSupported() {
// Ignores browsers that don't support the Performance Timing API.
if (window.performance && window.performance.timing) {
var navTiming = window.performance.timing;
var navStart = navTiming.navigationStart;
var fpTime;
// If chrome, get first paint time from `chrome.loadTimes`.
if (window.chrome && window.chrome.loadTimes) {
fpTime = window.chrome.loadTimes().firstPaintTime * 1000;
}
// If IE/Edge, use the prefixed `msFirstPaint` property.
// See http://msdn.microsoft.com/ff974719
else if (navTiming.msFirstPaint) {
fpTime = navTiming.msFirstPaint;
}
if (fpTime && navStart) {
return fpTime - navStart;
}
}
}
Nous pouvons maintenant écrire une autre fonction qui envoie un événement de non-interaction avec le temps de première peinture comme valeur: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
});
}
}
Après avoir écrit ces deux fonctions, notre code de suivi se présente comme suit:
// 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();
Notez que, selon le moment où le code ci-dessus s'exécute, les pixels peuvent déjà avoir été peints à l'écran ou non. Pour nous assurer que nous exécutons toujours ce code après la première peinture, nous avons reporté l'appel à sendTimeToFirstPaint()
jusqu'après l'événement load
. En fait, nous avons décidé de différer l'envoi de toutes les données analytiques jusqu'à ce que la page soit chargée afin de nous assurer que ces requêtes ne concurrencent pas le chargement d'autres ressources.
// 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();
});
Le code ci-dessus envoie firstpaint
fois à Google Analytics, mais ce n'est que la moitié de l'histoire. Nous devions tout de même suivre l'état du service worker, sans quoi nous ne pourrions pas comparer les temps de première peinture d'une page contrôlée par un service worker et d'une page non contrôlée.
Déterminer l'état du service worker
Pour déterminer l'état actuel du service worker, nous avons créé une fonction utilitaire qui renvoie l'une des trois valeurs suivantes:
- controlled: un service worker contrôle la page. Dans le cas d'IOWA, cela signifie également que tous les composants ont été mis en cache et que la page fonctionne hors connexion.
- compatible: le navigateur est compatible avec le service worker, mais celui-ci ne contrôle pas encore la page. Il s'agit de l'état attendu pour les nouveaux visiteurs.
- non compatible: le navigateur de l'utilisateur n'est pas compatible avec le service worker.
function getServiceWorkerStatus() {
if ('serviceWorker' in navigator) {
return navigator.serviceWorker.controller ? 'controlled' : 'supported';
} else {
return 'unsupported';
}
}
Cette fonction a récupéré l'état du service worker. L'étape suivante consistait à associer cet état aux données que nous envoyions à Google Analytics.
Suivre des données personnalisées avec des dimensions personnalisées
Par défaut, Google Analytics vous offre de nombreuses possibilités de subdiviser votre trafic total en groupes en fonction des attributs de l'utilisateur, de la session ou de l'interaction. Ces attributs sont appelés dimensions. Les dimensions courantes qui intéressent les développeurs Web sont, par exemple, Navigateur, Système d'exploitation ou Catégorie d'appareil.
L'état du service worker n'est pas une dimension fournie par défaut par Google Analytics. Toutefois, Google Analytics vous permet de créer vos propres dimensions personnalisées et de les définir comme vous le souhaitez.
Pour IOWA, nous avons créé une dimension personnalisée appelée État du service worker et défini son champ d'application sur appel (c'est-à-dire par interaction).4 Chaque dimension personnalisée que vous créez dans Google Analytics reçoit un indice unique dans cette propriété. Dans votre code de suivi, vous pouvez faire référence à cette dimension par son indice. Par exemple, si l'index de la dimension que nous venons de créer était 1, nous pourrions modifier notre logique comme suit pour envoyer l'événement firstpaint
afin d'inclure l'état du service worker:
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()
});
Cela fonctionne, mais n'associe l'état du service worker qu'à cet événement particulier. Étant donné que l'état du service worker peut être utile à connaître pour toute interaction, il est préférable de l'inclure avec toutes les données envoyées à Google Analytics.
Pour inclure ces informations dans tous les appels (par exemple, toutes les pages vues, tous les événements, etc.), nous définissons la valeur de la dimension personnalisée sur l'objet traceur lui-même, avant d'envoyer des données à Google Analytics.
ga('set', 'dimension1', getServiceWorkerStatus());
Une fois définie, cette valeur est envoyée avec tous les appels suivants pour le chargement de page en cours. Si l'utilisateur recharge la page plus tard, une nouvelle valeur sera probablement renvoyée par la fonction getServiceWorkerStatus()
et cette valeur sera définie sur l'objet du traceur.
Remarque rapide sur la clarté et la lisibilité du code: comme d'autres personnes qui examinent ce code peuvent ne pas savoir à quoi dimension1
fait référence, il est toujours préférable de créer une variable qui met en correspondance des noms de dimension pertinents avec les valeurs que analytics.js utilisera.
// 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();
});
Comme indiqué précédemment, envoyer la dimension État du service worker avec chaque appel nous permet de l'utiliser pour générer des rapports sur n'importe quelle métrique.
Comme vous pouvez le constater, près de 85% de toutes les pages vues pour l'Iowa provenaient de navigateurs compatibles avec les service workers.
Résultats: répondre à nos questions
Une fois que nous avons commencé à collecter des données pour répondre à nos questions, nous avons pu les analyser pour voir les résultats. (Remarque: toutes les données Google Analytics présentées ici représentent le trafic Web réel vers le site IOWA du 16 au 22 mai 2016.)
La première question que nous nous sommes posée était la suivante: Le cache du service worker est-il plus performant que les mécanismes de mise en cache HTTP existants disponibles dans tous les navigateurs ?
Pour répondre à cette question, nous avons créé un rapport personnalisé qui analysait la métrique Temps de chargement moyen des pages pour différentes dimensions. Cette métrique est bien adaptée pour répondre à cette question, car l'événement load
ne se déclenche qu'après le téléchargement de toutes les ressources initiales. Il reflète donc directement le temps de chargement total de toutes les ressources critiques du site.5
Les dimensions que nous avons choisies sont les suivantes:
- Notre dimension personnalisée État du service worker.
- Type d'utilisateur, qui indique s'il s'agit de la première visite de l'utilisateur sur le site ou s'il est un utilisateur connu. (Remarque: un nouveau visiteur n'aura aucune ressource mise en cache, contrairement à un visiteur régulier.)
- Catégorie d'appareil, qui permet de comparer les résultats sur mobile et sur ordinateur.
Pour vérifier que des facteurs non liés aux service workers ne faussaient pas nos résultats sur le temps de chargement, nous avons limité notre requête à inclure uniquement les navigateurs compatibles avec les service workers.
Comme vous pouvez le constater, les visites de notre application contrôlées par un service worker se chargent beaucoup plus rapidement que les visites non contrôlées, même celles des utilisateurs qui reviennent, qui ont probablement mis en cache la plupart des ressources de la page. Il est également intéressant de noter qu'en moyenne, les visiteurs sur mobile avec un service worker ont vu des chargements plus rapides que les nouveaux visiteurs sur ordinateur.
"…les visites de notre application lorsqu'elles sont contrôlées par un service worker se chargent beaucoup plus rapidement que les visites non contrôlées…"
Pour en savoir plus, consultez les deux tableaux suivants:
Temps de chargement moyen de la page (ordinateur) | |||
---|---|---|---|
État du service worker | Type d'utilisateur | Temps de chargement moyen de la page (ms) | Taille de l'échantillon |
A contrôlé | Visiteur connu | 2568 | 30860 |
Compatible | Visiteur connu | 3612 | 1289 |
Compatible | Nouveau visiteur | 4664 | 21991 |
Temps de chargement moyen de la page (mobile) | |||
---|---|---|---|
État du service worker | Type d'utilisateur | Temps de chargement moyen de la page (ms) | Taille de l'échantillon |
A contrôlé | Visiteur connu | 3760 | 8162 |
Compatible | Visiteur connu | 4843 | 676 |
Compatible | Nouveau visiteur | 6158 | 5779 |
Vous vous demandez peut-être comment un visiteur qui revient et dont le navigateur est compatible avec le service worker peut se trouver dans un état non contrôlé. Plusieurs raisons peuvent expliquer cette situation:
- L'utilisateur a quitté la page lors de la première visite avant que le service worker n'ait eu le temps de terminer son initialisation.
- L'utilisateur a désinstallé le service worker via les outils pour les développeurs.
Ces deux situations sont relativement rares. Pour le voir, examinez les valeurs de l'échantillon de chargement de page dans la quatrième colonne. Notez que les lignes du milieu comportent un échantillon beaucoup plus petit que les deux autres.
Notre deuxième question était la suivante: Quel est l'impact d'un service worker sur l'expérience de chargement du site ?
Pour répondre à cette question, nous avons créé un autre rapport personnalisé pour la métrique Valeur moyenne de l'événement et filtré les résultats pour n'inclure que nos événements firstpaint
. Nous avons utilisé les dimensions Catégorie d'appareil et notre dimension personnalisée État du service worker.
Contrairement à ce que j'aurais pu imaginer, le service worker sur mobile a eu beaucoup moins d'impact sur le temps de première peinture que sur le chargement global de la page.
"…le service worker sur mobile a eu beaucoup moins d'impact sur le délai de première peinture que sur le chargement global de la page."
Pour comprendre pourquoi, nous devons examiner plus en détail les données. Les moyennes peuvent être utiles pour obtenir une vue d'ensemble, mais pour avoir une idée précise de la répartition de ces chiffres sur un éventail d'utilisateurs, nous devons examiner une distribution sur firstpaint
fois.
Obtenir la distribution d'une métrique dans Google Analytics
Pour obtenir la distribution des temps firstpaint
, nous avons besoin d'accéder aux résultats individuels de chaque événement. Malheureusement, Google Analytics ne facilite pas cette tâche.
Google Analytics vous permet de répartir un rapport selon la dimension de votre choix, mais pas selon les métriques. Cela ne signifie pas que c'est impossible, mais simplement que nous avons dû personnaliser notre implémentation un peu plus pour obtenir le résultat souhaité.
Étant donné que les résultats des rapports ne peuvent être ventilés que par dimensions, nous avons dû définir la valeur de la métrique (dans ce cas, l'heure firstpaint
) en tant que dimension personnalisée sur l'événement. Pour ce faire, nous avons créé une autre dimension personnalisée appelée Valeur de la métrique et mis à jour notre logique de suivi firstpaint
comme suit:
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);
}
}
L'interface Web de Google Analytics ne permet pas actuellement de visualiser la distribution de valeurs de métriques arbitraires. Toutefois, avec l'aide de l'API Google Analytics Core Reporting et de la bibliothèque Google Charts, nous pouvons interroger les résultats bruts, puis créer nous-mêmes un histogramme.
Par exemple, la configuration de requête d'API suivante a été utilisée pour obtenir une distribution des valeurs firstpaint
sur ordinateur avec un service worker non contrôlé.
{
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'
}
]
}
Cette requête API renvoie un tableau de valeurs qui se présente comme suit (remarque: il ne s'agit que des cinq premiers résultats). Les résultats sont triés de la plus petite à la plus grande valeur. Ces lignes représentent donc les temps les plus rapides.
Résultats de la réponse de l'API (cinq premières lignes) | |
---|---|
ga:dimension2 | ga:totalEvents |
4 | 3 |
5 | 2 |
6 | 10 |
7 | 8 |
8 | 10 |
Voici ce que ces résultats signifient en langage clair:
- Trois événements pour lesquels la valeur
firstpaint
était de 4 ms - Deux événements pour lesquels la valeur
firstpaint
était de 5 ms - 10 événements pour lesquels la valeur
firstpaint
était de 6 ms - Huit événements ont eu lieu pour lesquels la valeur
firstpaint
était de 7 ms. - 10 événements pour lesquels la
firstpaint
value
était de 8 ms - etc.
À partir de ces résultats, nous pouvons extrapoler la valeur firstpaint
pour chaque événement et créer un histogramme de la distribution. Nous avons procédé ainsi pour chacune des requêtes que nous avons exécutées.
Voici à quoi ressemblait la distribution sur ordinateur avec un service worker non contrôlé (mais compatible) :
La durée firstpaint
médiane pour la distribution ci-dessus est de 912 ms.
La forme de cette courbe est assez typique des distributions de temps de chargement. Comparez-le à l'histogramme ci-dessous, qui montre la distribution des événements de première peinture pour les visites au cours desquelles un service worker contrôlait la page.
Notez que lorsque le contrôle de la page était assuré par un service worker, de nombreux visiteurs ont vu leur première peinture presque immédiate, avec une valeur médiane de 583 ms.
"…lorsqu'un service worker contrôlait la page, de nombreux visiteurs ont vu la première peinture presque immédiatement…"
Pour mieux comprendre la comparaison entre ces deux distributions, le graphique suivant présente une vue fusionnée des deux. L'histogramme des visites non contrôlées par le service worker est superposé à l'histogramme des visites contrôlées, et les deux sont superposés à un histogramme des deux combinés.
J'ai trouvé intéressant que la distribution avec un service worker contrôlé présente toujours une courbe en forme de cloche après le pic initial. Je m'attendais à un pic initial important, suivi d'une baisse progressive, mais pas à un deuxième pic dans la courbe.
Lorsque j'ai examiné la cause possible de ce problème, j'ai appris que même si un service worker peut contrôler une page, son thread peut être inactif. Le navigateur fait cela pour économiser des ressources. Il est évident que vous n'avez pas besoin que tous les services workers de tous les sites que vous avez déjà visités soient actifs et prêts à tout moment. Cela explique la queue de la distribution. Pour certains utilisateurs, un délai s'écoulait pendant le démarrage du thread du service worker.
Comme vous pouvez le voir dans la distribution, même avec ce délai initial, les navigateurs avec service worker ont diffusé le contenu plus rapidement que les navigateurs passant par le réseau.
Voici à quoi cela ressemblait sur mobile:
Bien que nous ayons constaté une augmentation importante des temps de première peinture quasi immédiats, la queue était beaucoup plus grande et plus longue. Cela est probablement dû au fait que, sur mobile, le démarrage d'un thread de service worker inactif prend plus de temps que sur ordinateur. Cela explique également pourquoi la différence entre la durée moyenne de firstpaint
n'était pas aussi importante que je l'attendais (voir ci-dessus).
"…sur mobile, le démarrage d'un thread de service worker inactif prend plus de temps que sur ordinateur."
Voici le détail de ces variations des temps de première peinture médians sur mobile et sur ordinateur, regroupés par état du service worker:
Temps médian avant le premier rendu (ms) | ||
---|---|---|
État du service worker | Ordinateur | Mobile |
A contrôlé | 583 | 1634 |
Compatible (non contrôlé) | 912 | 1933 |
Bien que la création de ces visualisations de distribution ait pris un peu plus de temps et d'efforts que la création d'un rapport personnalisé dans Google Analytics, elles nous donnent une bien meilleure idée de l'impact des services workers sur les performances de notre site que les moyennes seules.
Autres conséquences des service workers
En plus de l'impact sur les performances, les services workers ont également un impact sur l'expérience utilisateur de plusieurs autres manières mesurables avec Google Analytics.
Accès hors connexion
Les service workers permettent aux utilisateurs d'interagir avec votre site lorsqu'ils sont hors connexion. Bien qu'une certaine compatibilité hors connexion soit probablement essentielle pour toute application Web progressive, déterminer son importance dans votre cas dépend en grande partie de l'utilisation hors connexion. Mais comment pouvons-nous mesurer cela ?
Vous devez disposer d'une connexion Internet pour envoyer des données à Google Analytics, mais vous n'avez pas besoin de les envoyer au moment exact de l'interaction. Google Analytics permet d'envoyer des données d'interaction a posteriori en spécifiant un décalage temporel (via le paramètre qt
).
Depuis deux ans, IOWA utilise un script de service worker qui détecte les échecs d'appels à Google Analytics lorsque l'utilisateur est hors connexion et les lit à nouveau plus tard avec le paramètre qt
.
Pour savoir si l'utilisateur était en ligne ou hors connexion, nous avons créé une dimension personnalisée appelée En ligne et l'avons définie sur la valeur navigator.onLine
. Nous avons ensuite écouté les événements online
et offline
, puis mis à jour la dimension en conséquence.
Pour avoir une idée de la fréquence à laquelle les utilisateurs étaient hors connexion lorsqu'ils utilisaient IOWA, nous avons créé un segment qui ciblait les utilisateurs ayant au moins une interaction hors connexion. Il s'a avéré que cela concernait près de 5% des utilisateurs.
Notifications push
Les service workers permettent aux utilisateurs d'activer la réception de notifications push. Dans IOWA, les utilisateurs étaient avertis lorsqu'une session de leur planning était sur le point de commencer.
Comme pour toute forme de notification, il est important de trouver le juste équilibre entre apporter de la valeur à l'utilisateur et l'ennuyer. Pour mieux comprendre ce qui se passe, il est important de savoir si les utilisateurs acceptent de recevoir ces notifications, s'ils interagissent avec elles lorsqu'elles arrivent et si certains utilisateurs qui les avaient acceptées changent d'avis et les désactivent.
Dans IOWA, nous n'envoyions que des notifications liées au calendrier personnalisé de l'utilisateur, que seuls les utilisateurs connectés pouvaient créer. Cela limitait l'ensemble des utilisateurs pouvant recevoir des notifications aux utilisateurs connectés (suivi via une dimension personnalisée appelée Connecté) dont les navigateurs étaient compatibles avec les notifications push (suivi via une autre dimension personnalisée appelée Autorisation de notification).
Le rapport suivant est basé sur la métrique Utilisateurs et sur notre dimension personnalisée "Autorisation de notification", segmentée par les utilisateurs qui se sont connectés à un moment donné et dont les navigateurs sont compatibles avec les notifications push.
Nous sommes ravis de constater que plus de la moitié de nos utilisateurs connectés ont choisi de recevoir des notifications push.
Bannières incitant à installer une application
Si une progressive web app répond aux critères et est utilisée fréquemment par un utilisateur, une bannière d'installation de l'application peut s'afficher pour l'inviter à ajouter l'application à son écran d'accueil.
Dans l'Iowa, nous avons suivi la fréquence à laquelle ces requêtes étaient présentées à l'utilisateur (et si elles étaient acceptées) à l'aide du code suivant:
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
});
});
});
Parmi les utilisateurs qui ont vu une bannière d'installation d'application, environ 10% ont choisi de l'ajouter à leur écran d'accueil.
Améliorations possibles du suivi (pour la prochaine fois)
Les données analytiques que nous avons collectées auprès d'Iowa cette année ont été inestimables. Mais avec le recul, on voit toujours des lacunes et des possibilités d'amélioration pour la prochaine fois. Après avoir terminé l'analyse de cette année, voici deux choses que nous aurions aimé faire différemment et que les lecteurs qui souhaitent mettre en œuvre une stratégie similaire pourraient envisager:
1. Suivre plus d'événements liés à l'expérience de chargement
Nous avons suivi plusieurs événements qui correspondent à une métrique technique (par exemple, HTMLImportsLoaded, WebComponentsReady, etc.), mais comme une grande partie de la charge était effectuée de manière asynchrone, le moment où ces événements se sont déclenchés ne correspondait pas nécessairement à un moment particulier de l'expérience de chargement globale.
L'événement principal lié à la charge que nous n'avons pas suivi (mais que nous aurions aimé) est le moment où l'écran de démarrage a disparu et que l'utilisateur a pu voir le contenu de la page.
2. Stocker l'ID client d'analyse dans IndexedDB
Par défaut, analytics.js stocke le champ d'ID client dans les cookies du navigateur. Malheureusement, les scripts de service worker ne peuvent pas accéder aux cookies.
Cela nous a posé problème lorsque nous avons essayé d'implémenter le suivi des notifications. Nous voulions envoyer un événement à partir du service worker (via le protocole de mesure) chaque fois qu'une notification était envoyée à un utilisateur, puis suivre le succès du réengagement de cette notification si l'utilisateur a cliqué dessus et est revenu dans l'application.
Bien que nous ayons pu suivre le succès des notifications en général via le paramètre de campagne utm_source
, nous n'avons pas pu associer une session de réengagement spécifique à un utilisateur spécifique.
Pour contourner cette limitation, nous aurions pu stocker l'ID client via IndexedDB dans notre code de suivi. Cette valeur aurait alors été accessible au script du service worker.
3. Laisser le service worker signaler l'état en ligne/hors connexion
L'inspection de navigator.onLine
vous indique si votre navigateur peut se connecter au routeur ou au réseau local, mais ne vous indique pas nécessairement si l'utilisateur dispose d'une connectivité réelle. Et comme notre script de service de worker d'analyse hors connexion rejouait simplement les requêtes ayant échoué (sans les modifier ni les marquer comme ayant échoué), nous sous-estimions probablement notre utilisation hors connexion.
À l'avenir, nous devrions suivre à la fois l'état de navigator.onLine
et si l'appel a été rejoué par le service worker en raison d'un échec réseau initial. Nous disposerons ainsi d'une représentation plus précise de l'utilisation hors connexion réelle.
Conclusion
Cette étude de cas a montré que l'utilisation d'un service worker a effectivement amélioré les performances de chargement de l'application Web Google I/O sur un large éventail de navigateurs, de réseaux et d'appareils. Il a également démontré que lorsque vous examinez la distribution des données de charge sur un large éventail de navigateurs, de réseaux et d'appareils, vous obtenez beaucoup plus d'informations sur la façon dont cette technologie gère les scénarios réels et vous découvrez des caractéristiques de performances auxquelles vous ne vous attendiez peut-être pas.
Voici quelques-uns des principaux points à retenir de l'étude IOWA:
- En moyenne, les pages se chargeaient beaucoup plus rapidement lorsqu'un service worker les contrôlait que sans service worker, que les visiteurs soient nouveaux ou de retour.
- Les visites des pages contrôlées par un service worker se chargeaient presque instantanément pour de nombreux utilisateurs.
- Lorsqu'ils étaient inactifs, les services workers mettaient un certain temps à démarrer. Toutefois, un service worker inactif est toujours plus performant qu'un service worker inexistant.
- Le temps de démarrage d'un service worker inactif était plus long sur mobile que sur ordinateur.
Bien que les gains de performances observés dans une application particulière soient généralement utiles à communiquer à la communauté des développeurs, il est important de se rappeler que ces résultats sont spécifiques au type de site qu'est IOWA (un site d'événements) et au type d'audience qu'il a (principalement des développeurs).
Si vous implémentez un service worker dans votre application, il est important d'implémenter votre propre stratégie de mesure afin de pouvoir évaluer vos propres performances et éviter toute régression future. Si c'est le cas, n'hésitez pas à partager vos résultats pour que tout le monde puisse en profiter.
Notes de bas de page
- Il n'est pas tout à fait juste de comparer les performances de l'implémentation du cache du service worker aux performances de notre site avec le cache HTTP seul. Comme nous optimisions IOWA pour le service worker, nous n'avons pas passé beaucoup de temps à l'optimiser pour le cache HTTP. Si nous l'avions fait, les résultats auraient probablement été différents. Pour en savoir plus sur l'optimisation de votre site pour le cache HTTP, consultez Optimiser efficacement le contenu.
- Selon la façon dont votre site charge ses styles et son contenu, il est possible que le navigateur puisse peindre avant que le contenu ou les styles ne soient disponibles. Dans ce cas,
firstpaint
peut correspondre à un écran blanc vide. Si vous utilisezfirstpaint
, il est important de vous assurer qu'il correspond à un point significatif du chargement des ressources de votre site. - Techniquement, nous pourrions envoyer un coup de calendrier (qui ne sont pas des interactions par défaut) pour capturer ces informations au lieu d'un événement. En fait, les appels de date et heure ont été ajoutés à Google Analytics spécifiquement pour suivre les métriques de chargement de ce type. Toutefois, ils sont fortement échantillonnés au moment du traitement, et leurs valeurs ne peuvent pas être utilisées dans les segments. Compte tenu de ces limites actuelles, les événements sans interaction restent plus adaptés.
- Pour mieux comprendre le champ d'application à attribuer à une dimension personnalisée dans Google Analytics, consultez la section Dimension personnalisée du centre d'aide Analytics. Il est également important de comprendre le modèle de données Google Analytics, qui comprend les utilisateurs, les sessions et les interactions (appels). Pour en savoir plus, regardez la lecon de l'Académie Analytics sur le modèle de données Google Analytics.
- Cela ne tient pas compte des ressources chargées de manière paresseuse après l'événement de chargement.