Enregistrement d'un service worker

Bonnes pratiques pour programmer l'enregistrement de votre service worker.

Les service workers peuvent accélérer de manière significative les visites répétées sur votre application Web, mais vous devez prendre des mesures pour vous assurer que l'installation initiale d'un service worker ne dégrade pas l'expérience de première visite d'un utilisateur.

En règle générale, différer l'enregistrement du service worker jusqu'à ce que la page initiale soit chargée offre la meilleure expérience aux utilisateurs, en particulier ceux qui utilisent des appareils mobiles avec des connexions réseau plus lentes.

Texte récurrent pour l'enregistrement

Si vous avez déjà lu des informations sur les services workers, vous avez probablement rencontré un code standard semblable à celui-ci:

if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('/service-worker.js');
}

Cela peut parfois être accompagné de quelques instructions console.log() ou de code qui détecte une mise à jour d'un enregistrement de service worker précédent, afin d'indiquer aux utilisateurs de rafraîchir la page. Mais il ne s'agit que de légères variations sur les quelques lignes de code standards.

Existe-t-il une nuance pour navigator.serviceWorker.register ? Y a-t-il des bonnes pratiques à suivre ? Sans surprise (étant donné que cet article ne s'arrête pas ici), la réponse à ces deux questions est "oui".

Première visite d'un utilisateur

Prenons l'exemple de la première visite d'un utilisateur sur une application Web. Il n'y a pas encore de service worker, et le navigateur n'a aucun moyen de savoir à l'avance s'il y aura un service worker qui sera finalement installé.

En tant que développeur, votre priorité doit être de vous assurer que le navigateur obtient rapidement l'ensemble minimal de ressources critiques nécessaires pour afficher une page interactive. Tout ce qui ralentit la récupération de ces réponses est l'ennemi d'une expérience interactive rapide.

Imaginons maintenant que, lors du téléchargement du code JavaScript ou des images que votre page doit afficher, votre navigateur décide de démarrer un thread ou un processus en arrière-plan (par souci de concision, nous supposerons qu'il s'agit d'un thread). Supposons que vous n'utilisiez pas un ordinateur de bureau puissant, mais plutôt le type de téléphone mobile sous-puissant que la plupart des gens considèrent comme leur appareil principal. Le démarrage de ce thread supplémentaire ajoute un conflit pour le temps de processeur et la mémoire que votre navigateur pourrait autrement consacrer au rendu d'une page Web interactive.

Un thread d'arrière-plan inactif ne fera probablement pas une grande différence. Mais que se passe-t-il si ce thread n'est pas inactif, mais décide plutôt de commencer à télécharger des ressources à partir du réseau ? Toute préoccupation concernant la contention de processeur ou de mémoire doit passer au second plan par rapport aux inquiétudes concernant la bande passante limitée disponible pour de nombreux appareils mobiles. La bande passante est précieuse. Ne mettez donc pas en péril les ressources critiques en téléchargeant des ressources secondaires en même temps.

Tout cela signifie que le lancement d'un nouveau thread de service worker pour télécharger et mettre en cache des ressources en arrière-plan peut aller à l'encontre de votre objectif de fournir l'expérience la plus courte possible lors de la première visite d'un utilisateur sur votre site.

Améliorer le modèle

La solution consiste à contrôler le démarrage du service worker en choisissant quand appeler navigator.serviceWorker.register(). Une règle simple consiste à retarder l'enregistrement jusqu'à ce que load event se déclenche sur window, comme suit:

if ('serviceWorker' in navigator) {
    window.addEventListener('load', function() {
    navigator.serviceWorker.register('/service-worker.js');
    });
}

Toutefois, le bon moment pour lancer l'enregistrement du service worker peut également dépendre de ce que votre application Web fait juste après son chargement. Par exemple, l'application Web Google I/O 2016 comporte une courte animation avant de passer à l'écran principal. Notre équipe a découvert que le lancement de l'enregistrement du service worker pendant l'animation pouvait entraîner des à-coups sur les appareils mobiles bas de gamme. Plutôt que de proposer une mauvaise expérience aux utilisateurs, nous avons retardé l'enregistrement du service worker jusqu'après l'animation, lorsque le navigateur était le plus susceptible de passer quelques secondes à l'arrêt.

De même, si votre application Web utilise un framework qui effectue une configuration supplémentaire après le chargement de la page, recherchez un événement spécifique au framework qui signale la fin de cette tâche.

Visites ultérieures

Jusqu'à présent, nous nous sommes concentrés sur l'expérience de première visite, mais quel est l'impact de l'enregistrement différé du service worker sur les visites répétées sur votre site ? Bien que cela puisse surprendre certains utilisateurs, cela ne devrait pas avoir d'incidence.

Lorsqu'un service worker est enregistré, il passe par les événements de cycle de vie install et activate. Une fois qu'un service worker est activé, il peut gérer les événements fetch pour toutes les visites ultérieures de votre application Web. Le service worker démarre avant la requête pour toutes les pages de son champ d'application, ce qui est logique. Si le service worker existant n'était pas déjà en cours d'exécution avant la visite d'une page, il n'aurait pas la possibilité de traiter les événements fetch pour les requêtes de navigation.

Par conséquent, une fois qu'un service worker est actif, il n'a pas d'importance quand vous appelez navigator.serviceWorker.register(), ni même si vous l'appelez. Sauf si vous modifiez l'URL du script du service worker, navigator.serviceWorker.register() est effectivement une opération sans effet lors des visites suivantes. Le moment où il est appelé n'a pas d'importance.

Pourquoi s'inscrire à l'avance ?

Existe-t-il des scénarios dans lesquels enregistrer votre service worker le plus tôt possible est judicieux ? Par exemple, lorsque votre service worker utilise clients.claim() pour prendre le contrôle de la page lors de la première visite, et qu'il effectue de manière agressive un mise en cache d'exécution dans son gestionnaire fetch. Dans ce cas, il est avantageux d'activer le service worker le plus rapidement possible pour essayer de remplir ses caches d'exécution avec des ressources qui pourraient s'avérer utiles plus tard. Si votre application Web appartient à cette catégorie, il est utile de prendre du recul pour vous assurer que le gestionnaire install de votre service worker ne demande pas de ressources qui se disputent la bande passante avec les requêtes de la page principale.

Tester des choses

Pour simuler une première visite, ouvrez votre application Web dans une fenêtre Chrome Incognito, puis examinez le trafic réseau dans les outils pour les développeurs de Chrome. En tant que développeur Web, vous rechargez probablement une instance locale de votre application Web des dizaines de fois par jour. Toutefois, en revisitant votre site lorsqu'il existe déjà un service worker et des caches entièrement remplis, vous n'obtenez pas la même expérience qu'un nouvel utilisateur, et il est facile d'ignorer un problème potentiel.

Voici un exemple illustrant l'impact du moment de l'enregistrement. Les deux captures d'écran ont été prises lors de la visite d'une application exemple en mode navigation privée à l'aide du débit limité du réseau pour simuler une connexion lente.

Trafic réseau avec enregistrement anticipé.

La capture d'écran ci-dessus reflète le trafic réseau lorsque l'exemple a été modifié pour effectuer l'enregistrement du service worker dès que possible. Vous pouvez voir les requêtes de préchargement (les entrées avec l'icône en forme de roue dentée à côté, provenant du gestionnaire install du service worker) entrecoupées de requêtes pour les autres ressources nécessaires à l'affichage de la page.

Trafic réseau avec enregistrement tardif

Dans la capture d'écran ci-dessus, l'enregistrement du service worker a été retardé jusqu'à la fin du chargement de la page. Vous pouvez constater que les requêtes de préchargement ne commencent pas tant que toutes les ressources n'ont pas été extraites du réseau, ce qui élimine toute contention de bande passante. De plus, comme certains des éléments que nous préchargeons se trouvent déjà dans le cache HTTP du navigateur (les éléments avec (from disk cache) dans la colonne "Taille"), nous pouvons remplir le cache du service worker sans avoir à accéder à nouveau au réseau.

Vous pouvez gagner des points bonus si vous exécutez ce type de test à partir d'un appareil bas de gamme réel sur un réseau mobile réel. Vous pouvez profiter des fonctionnalités de débogage à distance de Chrome pour connecter un téléphone Android à votre ordinateur de bureau via USB et vous assurer que les tests que vous exécutez reflètent réellement l'expérience réelle de nombreux utilisateurs.

Conclusion

Pour résumer, vous devez faire de l'expérience de première visite de vos utilisateurs votre priorité absolue. Pour vous en assurer, vous pouvez retarder l'enregistrement du service worker jusqu'à ce que la page ait été chargée lors de la visite initiale. Vous bénéficierez toujours de tous les avantages d'un service worker pour vos visites répétées.

Pour retarder l'enregistrement initial de votre service worker jusqu'à ce que la première page soit chargée, vous pouvez utiliser ce code:

if ('serviceWorker' in navigator) {
    window.addEventListener('load', function() {
    navigator.serviceWorker.register('/service-worker.js');
    });
}