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.

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 ce ne sont que des variations mineures par rapport aux quelques lignes de code standards.

Existe-t-il une nuance pour navigator.serviceWorker.register ? Existe-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 qu'au cours du téléchargement du code JavaScript ou des images que votre page doit afficher, votre navigateur décide de lancer un thread ou un processus en arrière-plan (par souci de concision, nous considérons 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 fait votre application Web 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 d'offrir une expérience utilisateur médiocre, nous avons retardé l'inscription d'un service worker jusqu'à la fin de l'animation, période à laquelle le navigateur a le plus de chances d'attendre quelques secondes d'inactivité.

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 certaines personnes, cela ne devrait pas avoir d’impact du tout.

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 de consulter une page, il n'aurait pas la possibilité de traiter les événements fetch pour les requêtes de navigation.

Une fois qu'un service worker est actif, ce n'est pas important lorsque vous appelez navigator.serviceWorker.register(), ou même même si vous l'appelez. À moins que vous ne modifiiez l'URL du script de service worker, navigator.serviceWorker.register() est effectivement une no-op 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 il est judicieux d'enregistrer votre service worker le plus tôt possible ? 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 au moment de l'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

Un excellent moyen de simuler une première visite consiste à ouvrir votre application Web dans une fenêtre de navigation privée Chrome et à examiner le trafic réseau dans les Outils de développement 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'au chargement de la page. Comme vous pouvez le constater, les requêtes de mise en cache préalable ne démarrent que lorsque toutes les ressources ont été extraites du réseau, ce qui élimine tout conflit pour la bande passante. De plus, comme certains éléments pour lesquels nous effectuons une pré-mise en cache 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, s'assurer que vos utilisateurs bénéficient de la meilleure expérience de première visite doit être une 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 liés à l'utilisation 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');
    });
}