Enregistrement d'un service worker

Bonnes pratiques pour chronométrer l'enregistrement d'un service worker.

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

En règle générale, reporter l'enregistrement d'un service worker jusqu'à la fin du chargement de la page initiale offre une expérience optimale aux utilisateurs, en particulier sur les appareils mobiles dont la connexion réseau est plus lente.

Code récurrent pour l'enregistrement

Si vous avez déjà lu des informations sur les service workers, vous avez probablement trouvé des sujets récurrents semblables à ce qui suit:

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

Cela peut parfois être accompagné de quelques instructions console.log() ou de quelques codes qui détectent une mise à jour d'un enregistrement précédent d'un service worker, afin d'informer les utilisateurs qu'ils doivent actualiser la page. Mais ce ne sont que des variations mineures sur les quelques lignes de code standards.

Y a-t-il donc des nuances avec navigator.serviceWorker.register ? Y a-t-il des meilleures pratiques à suivre ? Sans surprise (étant donné que cet article ne s'arrête pas ici), la réponse aux 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 qui nécessite un délai d'interaction rapide.

Imaginez 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 supposons qu'il s'agit d'un thread). Supposons que vous n'utilisiez pas un ordinateur de bureau robuste, mais un type de téléphone mobile peu puissant que la plupart des utilisateurs dans le monde considèrent comme leur appareil principal. L'activation de ce thread supplémentaire crée des conflits pour le temps CPU et la mémoire que votre navigateur pourrait autrement consacrer à l'affichage d'une page Web interactive.

Il est peu probable qu'un thread d'arrière-plan inactif fasse une différence significative. Mais que se passe-t-il si ce thread n'est pas inactif, mais qu'il décide qu'il va également commencer à télécharger des ressources à partir du réseau ? Toute préoccupation concernant un conflit de processeur ou de mémoire doit passer au second plan afin de s'inquiéter de la bande passante limitée disponible pour de nombreux appareils mobiles. La bande passante est précieuse, donc ne sapez pas les ressources critiques en téléchargeant des ressources secondaires en même temps.

En d'autres termes, lancer un nouveau thread de service worker pour télécharger et mettre en cache les ressources en arrière-plan peut aller à l'encontre de votre objectif qui consiste à offrir le plus court délai d'interaction lors de la première visite d'un utilisateur sur votre site.

Améliorer le code récurrent

La solution consiste à contrôler le démarrage du service worker en choisissant quand appeler navigator.serviceWorker.register(). Une règle d'or consiste à différer l'enregistrement jusqu'au déclenchement de load event sur window, comme ceci:

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

Toutefois, le bon moment pour lancer l'enregistrement d'un 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 propose une courte animation avant de passer à l'écran principal. Notre équipe a constaté que le lancement de l'inscription du service worker pendant l'animation pouvait entraîner des à-coups sur les appareils mobiles bas de gamme. Plutôt que de nuire à l'expérience utilisateur, nous avons retardé l'enregistrement d'un service worker jusqu'à la fin de l'animation, moment auquel le navigateur était le plus susceptible d'avoir 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 quand ce travail est terminé.

Visites suivantes

Jusqu'à présent, nous nous sommes concentrés sur l'expérience des premières visites. Mais quel impact un retard d'enregistrement d'un service worker a-t-il sur les visites répétées sur votre site ? Bien que cela puisse surprendre certaines personnes, il ne devrait y avoir aucun impact.

Lorsqu'un service worker est enregistré, il est soumis aux é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 toute visite ultérieure de votre application Web. Il démarre avant la requête de pages de son champ d'application, ce qui est logique lorsque vous y réfléchissez. 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.

Ainsi, une fois qu'il y a un service worker actif, le moment où vous appelez navigator.serviceWorker.register() ou, en fait, vous l'appelez n'a pas d'importance. À moins que vous ne modifiiez l'URL du script du service worker, navigator.serviceWorker.register() sera en réalité une no-op lors des visites suivantes. Le moment de l'appel n'a pas d'importance.

Pourquoi s'inscrire plus tôt

Existe-t-il des scénarios dans lesquels il est judicieux d'enregistrer votre service worker le plus tôt possible ? Vous vous souviendrez 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 une mise en cache de l'environnement d'exécution dans son gestionnaire fetch. Dans ce cas, il y a l'avantage 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 ultérieurement. Si votre application Web entre dans 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 luttent pour la bande passante avec les requêtes de la page principale.

Tester

Un excellent moyen de simuler une première visite consiste à ouvrir votre application Web dans une fenêtre de navigation privée Chrome, puis à 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 et des dizaines de fois par jour. Toutefois, en revenant sur votre site alors qu'il y a déjà un service worker et des caches entièrement remplis, vous n'obtiendrez pas la même expérience qu'un nouvel utilisateur, et vous pourrez facilement ignorer un problème potentiel.

Voici un exemple illustrant la différence que le délai d'enregistrement peut faire. Les deux captures d'écran sont effectuées lors de la visite d'un application exemple en mode navigation privée à l'aide de la limitation 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'échantillon a été modifié pour procéder à l'enregistrement du service worker dès que possible. Vous pouvez voir les requêtes de mise en cache préalable (les entrées accompagnées de l'icône en forme de roue dentée, 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 d'un 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 les conflits de bande passante. De plus, comme certains des éléments que nous mettons en pré-mise en cache se trouvent déjà dans le cache HTTP du navigateur (ceux dont la colonne contient (from disk cache) dans la colonne Size), nous pouvons remplir le cache du service worker sans avoir à accéder à nouveau au réseau.

C'est encore mieux si vous exécutez ce type de test à partir d'un appareil d'entrée de gamme réelle sur un vrai réseau mobile. Vous pouvez utiliser les 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 bien l'expérience réelle de nombreux utilisateurs.

Conclusion

En résumé, vous devez vous assurer que vos utilisateurs bénéficient de la meilleure expérience de première visite possible. Pour cela, il peut être utile de différer l'inscription d'un service worker après le chargement de la page lors de la visite initiale. Vous bénéficierez toujours de tous les avantages d'un service worker lors de vos visites répétées.

Un moyen simple de retarder l'inscription initiale de votre service worker jusqu'au chargement de la première page consiste à utiliser le code suivant:

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