Utiliser les Workers de service pour gérer les demandes réseau

Les Workers de service sont un type spécial de Web Workers qui peut intercepter, modifier et répondre aux requêtes réseau à l’aide de l’API Fetch . Les workers de service peuvent accéder à l’API Cache et aux magasins de données côté client asynchrones, tels que IndexedDB, pour stocker des ressources.

Les workers de service peuvent accélérer votre PWA en mettant en cache les ressources localement, et ils peuvent également rendre votre PWA plus fiable en la rendant indépendante du réseau.

La première fois qu’un utilisateur accède à votre PWA, son Service Worker est installé. Le Service Worker s’exécute ensuite en parallèle à votre application et peut continuer à travailler même si votre application n’est pas en cours d’exécution.

Les workers de service sont responsables de l’interception, de la modification et de la réponse aux demandes réseau. Ils peuvent être alertés lorsque l’application tente de charger une ressource à partir du serveur ou envoie une demande pour obtenir des données à partir du serveur. Dans ce cas, un Service Worker peut décider de laisser la requête aller au serveur, ou de l’intercepter et de retourner une réponse à partir du cache à la place.

Diagramme d’architecture de haut niveau montrant que le Service Worker se trouve entre l’application et le stockage réseau et cache

Inscrire un Service Worker

Comme pour les autres workers web, les workers de service doivent exister dans un fichier distinct. Vous référencez ce fichier lors de l’inscription du Service Worker, comme indiqué dans le code suivant :

if ("serviceWorker" in navigator) {
    navigator.serviceWorker.register("/serviceworker.js");
}

Le navigateur web qui exécute votre PWA peut fournir différents niveaux de prise en charge pour les travailleurs du service. En outre, le contexte dans lequel votre PWA s’exécute peut ne pas être sécurisé. Par conséquent, il est recommandé de tester l’existence de l’objet navigator.serviceWorker avant d’exécuter tout code lié à Service Worker. Dans le code ci-dessus, un Service Worker est inscrit à l’aide du serviceworker.js fichier situé à la racine du site.

Veillez à placer le fichier Service Worker dans le répertoire de niveau le plus élevé que vous souhaitez qu’il gère. Un tel répertoire est appelé l’étendue du Service Worker. Dans le code précédent, le fichier est stocké dans le répertoire racine de votre application, et le Service Worker gère toutes les pages qui se trouvent sous le nom de domaine de l’application.

Si le fichier Service Worker a été stocké dans un js répertoire, l’étendue du Service Worker est limitée au js répertoire et aux sous-répertoires. Il est recommandé de placer le fichier Service Worker à la racine de votre application, sauf si vous avez besoin de réduire l’étendue de votre Service Worker.

Intercepter les demandes

L’événement main que vous utilisez dans un Service Worker est l’événement fetch . L’événement fetch s’exécute chaque fois que le navigateur exécuté par votre application tente d’accéder au contenu dans l’étendue du Service Worker.

Le code suivant montre comment ajouter un écouteur pour l’événement fetch :

self.addEventListener("fetch", event => {
  console.log('WORKER: Fetching', event.request);
});

Dans le fetch gestionnaire, vous pouvez contrôler si une requête est envoyée au réseau, si elle est extraite du cache, etc. L’approche que vous adopterez varie probablement en fonction du type de ressource demandée, de la fréquence à laquelle elle est mise à jour et d’autres logiques métier propres à votre application.

Voici quelques exemples de ce que vous pouvez faire dans le fetch gestionnaire :

  • Si disponible, retournez une réponse à partir du cache ; sinon, de secours pour demander la ressource sur le réseau.
  • Récupérez une ressource à partir du réseau, mettez en cache une copie et retournez la réponse.
  • Autoriser les utilisateurs à spécifier une préférence pour enregistrer les données.
  • Fournissez une image d’espace réservé pour certaines demandes d’image.
  • Générez une réponse directement dans service Worker.

Cycle de vie du Service Worker

Le cycle de vie d’un Service Worker se compose de plusieurs étapes, chaque étape déclenchant un événement. Vous pouvez ajouter des écouteurs à ces événements pour exécuter du code afin d’effectuer une action. La liste suivante présente une vue d’ensemble du cycle de vie et des événements associés des Travailleurs du service.

  1. Inscrivez le Service Worker.

  2. Le navigateur télécharge le fichier JavaScript, installe le Service Worker et déclenche l’événement install . Vous pouvez utiliser l’événement install pour pré-mettre en cache tous les fichiers importants et de longue durée (tels que des fichiers CSS, des fichiers JavaScript, des images de logo ou des pages hors connexion) à partir de votre application.

    self.addEventListener("install", event => {
        console.log("WORKER: install event in progress.");
    });
    
  3. Le Service Worker est activé, ce qui déclenche l’événement activate . Utilisez cet événement pour propre des caches obsolètes.

    self.addEventListener("activate", event => {
        console.log("WORKER: activate event in progress.");
    });
    
  4. Le Service Worker est prêt à s’exécuter lorsque la page est actualisée ou lorsque l’utilisateur accède à une nouvelle page sur le site. Si vous souhaitez exécuter le Service Worker sans attendre, utilisez la self.skipWaiting() méthode pendant l’événement install , comme suit :

    self.addEventListener("install", event => {
        self.skipWaiting();
        // …
    });
    
  5. Le Service Worker est maintenant en cours d’exécution et peut écouter fetch les événements.

Ressources de pré-mise en cache

Lorsqu’un utilisateur accède à votre application pour la première fois, le Service Worker de l’application est installé. Utilisez l’événement install dans votre Service Worker pour détecter quand cela se produit et mettre en cache toutes les ressources statiques dont votre application a besoin. La mise en cache des ressources statiques de votre application (telles que le code HTML, CSS et JavaScript) nécessaires à la page de démarrage permet à votre application de s’exécuter même lorsque l’appareil de l’utilisateur est hors connexion.

Pour mettre en cache les ressources de votre application, utilisez l’objet global caches et la cache.addAll méthode, comme indiqué ci-dessous :

// The name of the cache your app uses.
const CACHE_NAME = "my-app-cache";
// The list of static files your app needs to start.
const PRE_CACHED_RESOURCES = ["/", "styles.css", "app.js"];

// Listen to the `install` event.
self.addEventListener("install", event => {
  async function preCacheResources() {
    // Open the app's cache.
    const cache = await caches.open(CACHE_NAME);
    // Cache all static resources.
    cache.addAll(PRE_CACHED_RESOURCES);
  }

  event.waitUntil(preCacheResources());
});

Notez qu’après l’installation initiale, l’événement install ne s’exécute plus. Pour mettre à jour le code de votre Service Worker, consultez Mettre à jour votre Service Worker.

Vous pouvez maintenant utiliser l’événement fetch pour retourner les ressources statiques à partir du cache, au lieu de les charger à nouveau à partir du réseau :

self.addEventListener("fetch", event => {
  async function returnCachedResource() {
    // Open the app's cache.
    const cache = await caches.open(CACHE_NAME);
    // Find the response that was pre-cached during the `install` event.
    const cachedResponse = await cache.match(event.request.url);

    if (cachedResponse) {
      // Return the resource.
      return cachedResponse;
    } else {
      // The resource wasn't found in the cache, so fetch it from the network.
      const fetchResponse = await fetch(event.request.url);
      // Put the response in cache.
      cache.put(event.request.url, fetchResponse.clone());
      // And return the response.
      return fetchResponse.
    }
  }

  event.respondWith(returnCachedResource());
});

Par souci de concision, l’exemple de code ci-dessus ne gère pas les cas où l’obtention de l’URL de la requête à partir du réseau a échoué.

Utiliser une page hors connexion personnalisée

Lorsque votre application utilise plusieurs pages HTML, un scénario courant en mode hors connexion consiste à rediriger les demandes de navigation vers une page d’erreur personnalisée lorsque l’appareil de l’utilisateur est hors connexion :

// The name of the cache your app uses.
const CACHE_NAME = "my-app-cache";
// The list of static files your app needs to start.
// Note the offline page in this list.
const PRE_CACHED_RESOURCES = ["/", "styles.css", "app.js", "/offline"];

// Listen to the `install` event.
self.addEventListener("install", event => {
  async function preCacheResources() {
    // Open the app's cache.
    const cache = await caches.open(CACHE_NAME);
    // Cache all static resources.
    cache.addAll(PRE_CACHED_RESOURCES);
  }

  event.waitUntil(preCacheResources());
});

self.addEventListener("fetch", event => {
  async function navigateOrDisplayOfflinePage() {
    try {
      // Try to load the page from the network.
      const networkResponse = await fetch(event.request);
      return networkResponse;
    } catch (error) {
      // The network call failed, the device is offline.
      const cache = await caches.open(CACHE_NAME);
      const cachedResponse = await cache.match("/offline");
      return cachedResponse;
    }
  }

  // Only call event.respondWith() if this is a navigation request
  // for an HTML page.
  if (event.request.mode === 'navigate') {
    event.respondWith(navigateOrDisplayOfflinePage());
  }
});

Mettre à jour votre Service Worker

Installer une nouvelle version de Service Worker

Si vous apportez des modifications à votre code Service Worker et déployez le nouveau fichier Service Worker sur votre serveur web, les appareils de vos utilisateurs commenceront progressivement à utiliser le nouveau Service Worker.

Chaque fois qu’un utilisateur accède à l’une des pages de votre application, le navigateur qui exécute l’application vérifie si une nouvelle version du Service Worker est disponible sur le serveur. Le navigateur détecte les nouvelles versions en comparant le contenu entre le Service Worker existant et le nouveau Service Worker. Lorsqu’une modification est détectée, le nouveau Service Worker est installé (son install événement est déclenché), puis le nouveau Service Worker attend que le Service Worker existant cesse d’être utilisé sur l’appareil.

Dans la pratique, cela signifie qu’il peut y avoir deux Service Workers en cours d’exécution en même temps, mais qu’un seul intercepte les requêtes réseau de l’application. Lorsque l’application est fermée, le Service Worker existant cesse d’être utilisé. La prochaine fois que l’application est ouverte, le nouveau Service Worker est activé. L’événement activate est déclenché et le nouveau Service Worker commence à intercepter les fetch événements.

Vous pouvez activer de force le nouveau Service Worker dès qu’il est installé, en utilisant self.skipWaiting() dans le gestionnaire d’événements de install votre Service Worker.

Pour en savoir plus sur la mise à jour de Service Workers, consultez Mise à jour du Service Worker sur web.dev.

Mettre à jour vos fichiers statiques mis en cache

Lors de la pré-mise en cache de ressources statiques telles que les fichiers de feuille de style CSS, comme décrit dans Ressources de pré-mise en cache, votre application utilise uniquement les versions mises en cache des fichiers et n’essaie pas de télécharger de nouvelles versions.

Pour vous assurer que les utilisateurs obtiennent les dernières modifications apportées aux ressources statiques utilisées par votre application, utilisez une convention de nommage de mise en cache et mettez à jour votre code Service Worker.

Le busting du cache signifie que chaque fichier statique est nommé en fonction de sa version. Cela peut être réalisé de différentes façons, mais implique généralement l’utilisation d’un outil de génération qui lit le contenu d’un fichier et génère un ID unique basé sur le contenu. Cet ID peut être utilisé pour nommer le fichier statique mis en cache.

Ensuite, mettez à jour votre code Service Worker pour mettre en cache les nouvelles ressources statiques pendant install:

// The name of the new cache your app uses.
const CACHE_NAME = "my-app-cache-v2";
// The list of static files your app needs to start.
const PRE_CACHED_RESOURCES = ["/", "styles-124656.css", "app-576391.js"];

// Listen to the `install` event.
self.addEventListener("install", event => {
  async function preCacheResources() {
    // Open the app's cache.
    const cache = await caches.open(CACHE_NAME);
    // Cache the new static resources.
    cache.addAll(PRE_CACHED_RESOURCES);
  }

  event.waitUntil(preCacheResources());
});

// Listen to the `activate` event to clear old caches.
self.addEventListener("activate", event => {
  async function deleteOldCaches() {
    // List all caches by their names.
    const names = await caches.keys();
    await Promise.all(names.map(name => {
      if (name !== CACHE_NAME) {
        // If a cache's name is the current name, delete it.
        return caches.delete(name);
      }
    }));
  }

  event.waitUntil(deleteOldCaches());
});

Comparez les CACHE_NAME valeurs et PRE_CACHED_RESOURCES entre l’extrait de code ci-dessus et celui des ressources de pré-mise en cache. Lorsque ce nouveau Service Worker est installé, un nouveau cache est créé et les nouvelles ressources statiques sont téléchargées et mises en cache. Lorsque le Service Worker est activé, l’ancien cache est supprimé. À ce stade, l’utilisateur disposera de la nouvelle version de l’application.

Apporter des modifications à votre Service Worker peut parfois être complexe. Utilisez une bibliothèque telle que Workbox pour simplifier l’étape de génération de vos ressources statiques et votre code Service Worker.

Tester les connexions réseau dans votre PWA

Il est utile de savoir quand une connexion réseau est disponible, afin de synchroniser les données ou d’informer les utilisateurs que le status réseau a changé.

Utilisez les options suivantes pour tester la connectivité réseau :

La navigator.onLine propriété est une valeur booléenne qui vous permet de connaître la status actuelle du réseau. Si la valeur est true, l’utilisateur est en ligne ; sinon, l’utilisateur est hors connexion.

Pour plus d’informations , consultez navigator.onLine sur MDN.

Événements en ligne et hors connexion

Vous pouvez prendre des mesures lorsque votre connectivité réseau change. Vous pouvez écouter et prendre des mesures en réponse aux événements réseau. Les événements sont disponibles sur les windowéléments , documentet document.body , comme indiqué ci-dessous :

window.addEventListener("online",  function(){
    console.log("You are online!");
});
window.addEventListener("offline", function(){
    console.log("Oh no, you lost your network connection.");
});

Pour en savoir plus, consultez Navigator.onLine sur MDN.

Autres fonctionnalités

La responsabilité main d’un Service Worker est de rendre votre application plus rapide et plus fiable en cas de connexion réseau instable. Les Travailleurs du service utilisent principalement l’événement fetch et Cache l’API pour ce faire, mais ils peuvent utiliser d’autres API pour des scénarios avancés, tels que :

  • Synchronisation en arrière-plan des données.
  • Synchronisation périodique des données.
  • Téléchargements de fichiers en arrière-plan volumineux.
  • Gestion et notifications des messages Push.

Synchronisation en arrière-plan

Utilisez l’API de synchronisation en arrière-plan pour permettre aux utilisateurs de continuer à utiliser votre application et d’effectuer des actions même lorsque l’appareil de l’utilisateur est hors connexion.

Par exemple, une application de messagerie peut permettre à ses utilisateurs de composer et d’envoyer des messages à tout moment. Le serveur frontal de l’application peut essayer d’envoyer le message immédiatement, et si l’appareil est hors connexion, le Service Worker peut intercepter la demande ayant échoué et utiliser l’API de synchronisation en arrière-plan pour différer la tâche jusqu’à ce qu’il soit connecté.

Pour plus d’informations, consultez Utiliser l’API de synchronisation en arrière-plan pour synchroniser les données avec le serveur.

Synchronisation en arrière-plan de période

L’API périodique de synchronisation en arrière-plan permet aux PWA de récupérer régulièrement du contenu nouveau, en arrière-plan, afin que les utilisateurs puissent accéder immédiatement au contenu lorsqu’ils ouvriront l’application ultérieurement.

À l’aide de l’API de synchronisation en arrière-plan périodique, les PWA n’ont pas besoin de télécharger de nouveaux contenus (tels que de nouveaux articles) pendant que l’utilisateur utilise l’application. Le téléchargement de contenu peut ralentir l’expérience, de sorte que l’application peut récupérer le contenu à un moment plus pratique.

Pour plus d’informations, consultez Utiliser l’API de synchronisation en arrière-plan périodique pour obtenir régulièrement du contenu actualisé.

Téléchargements de fichiers d’arrière-plan volumineux

L’API De récupération en arrière-plan permet aux PWA de déléguer complètement le téléchargement de grandes quantités de données au moteur du navigateur. De cette façon, l’application et le Service Worker n’ont pas besoin d’être en cours d’exécution pendant le téléchargement.

Cette API est utile pour les applications qui permettent aux utilisateurs de télécharger des fichiers volumineux (tels que de la musique, des films ou des podcasts) pour des cas d’usage hors connexion. Le téléchargement est délégué au moteur du navigateur, qui sait comment gérer une connexion intermittente ou même une perte complète de connectivité.

Pour plus d’informations, consultez Utiliser l’API d’extraction en arrière-plan pour extraire des fichiers volumineux lorsque l’application ou service Worker n’est pas en cours d’exécution.

Messages Push

Des messages Push peuvent être envoyés à vos utilisateurs sans qu’ils n’utilisent l’application à ce moment-là. Un Service Worker peut écouter les messages Push envoyés par votre serveur même si l’application n’est pas en cours d’exécution et afficher une notification dans le centre de notifications du système d’exploitation.

Pour en savoir plus, consultez Réengager les utilisateurs avec des messages Push.

Déboguer avec DevTools

À l’aide de Microsoft Edge DevTools, vous pouvez voir si votre Service Worker a été inscrit correctement et voir dans quel état de cycle de vie le Service Worker se trouve actuellement. En outre, vous pouvez déboguer le code JavaScript dans votre Service Worker.

Pour plus d’informations, consultez Déboguer votre Service Worker.

Voir aussi