Diffusion

L'un des aspects clés des progressive web apps est qu'elles sont fiables. Elles permettent de charger les éléments rapidement, de préserver l'engagement des utilisateurs et de fournir des commentaires immédiatement, même lorsque le réseau est en mauvais état. Comment est-ce possible ? Grâce à l'événement fetch du service worker.

Événement de récupération

Navigateurs pris en charge

  • 40
  • 17
  • 44
  • 11.1

Source

L'événement fetch nous permet d'intercepter toutes les requêtes réseau effectuées par la PWA dans le champ d'application du service worker, à la fois pour les requêtes d'origine identique et multi-origine. En plus des demandes de navigation et d'éléments, l'extraction depuis un service worker installé permet d'afficher les pages consultées après le premier chargement d'un site sans appels réseau.

Le gestionnaire fetch reçoit toutes les requêtes d'une application, y compris les URL et les en-têtes HTTP, et laisse le développeur de l'application décider comment les traiter.

Le service worker est situé entre le client et le réseau.

Votre service worker peut transférer une requête au réseau, renvoyer une réponse précédemment mise en cache ou créer une réponse. Le choix vous appartient. Prenons un exemple simple :

self.addEventListener("fetch", event => {
    console.log(`URL requested: ${event.request.url}`);
});

Répondre à une requête

Lorsqu'une requête arrive à votre service worker, vous avez deux possibilités : l'ignorer et la laisser passer au réseau, ou y répondre. Répondre aux requêtes depuis votre service worker permet de choisir les éléments à renvoyer à votre PWA et de quelle manière, même lorsque l'utilisateur est hors connexion.

Pour répondre à une requête entrante, appelez event.respondWith() depuis un gestionnaire d'événements fetch, comme ceci:

// fetch event handler in your service worker file
self.addEventListener("fetch", event => {
    const response = .... // a response or a Promise of response
    event.respondWith(response);
});

Vous devez appeler respondWith() de manière synchrone et renvoyer un objet Response. En revanche, vous ne pouvez pas appeler respondWith() une fois que le gestionnaire d'événements de récupération a terminé, comme dans un appel asynchrone. Si vous devez attendre la réponse complète, vous pouvez transmettre à respondWith() une promesse qui se résout avec une réponse.

Créer des réponses

L'API Fetch vous permet de créer des réponses HTTP dans votre code JavaScript. Ces réponses peuvent être mises en cache à l'aide de l'API Cache Storage et renvoyées comme si elles provenaient d'un serveur Web.

Pour générer une réponse, créez un objet Response en définissant son corps et des options telles que l'état et les en-têtes:

const simpleResponse = new Response("Body of the HTTP response");

const options = {
   status: 200,
   headers: {
    'Content-type': 'text/html'
   }
};
const htmlResponse = new Response("<b>HTML</b> content", options)

Répondre à partir du cache

Maintenant que vous savez comment diffuser des réponses HTTP à partir d'un service worker, vous pouvez utiliser l'interface de mise en cache pour stocker des éléments sur l'appareil.

Vous pouvez utiliser l'API de stockage du cache pour vérifier si la requête reçue de la PWA est disponible dans le cache et, le cas échéant, répondre à respondWith() avec elle. Pour ce faire, vous devez d'abord effectuer une recherche dans le cache. La fonction match(), disponible dans l'interface caches de premier niveau, recherche dans tous les magasins de votre origine ou dans un seul objet de cache ouvert.

La fonction match() reçoit une requête HTTP ou une URL en tant qu'argument, et renvoie une promesse qui se résout avec la réponse associée à la clé correspondante.

// Global search on all caches in the current origin
caches.match(urlOrRequest).then(response => {
   console.log(response ? response : "It's not in the cache");
});

// Cache-specific search
caches.open("pwa-assets").then(cache => {
  cache.match(urlOrRequest).then(response => {
    console.log(response ? response : "It's not in the cache");
  });
});

Stratégies de mise en cache

La diffusion de fichiers uniquement à partir du cache du navigateur ne convient pas à tous les cas d'utilisation. Par exemple, l'utilisateur ou le navigateur peut supprimer le cache. C'est pourquoi vous devez définir vos propres stratégies de diffusion des éléments de votre PWA. Vous n'êtes pas limité à une seule stratégie de mise en cache. Vous pouvez en définir plusieurs selon le format d'URL. Par exemple, vous pouvez avoir une stratégie pour les éléments d'interface utilisateur minimaux, une autre pour les appels d'API et une troisième pour les URL d'image et de données. Pour ce faire, consultez event.request.url dans ServiceWorkerGlobalScope.onfetch et analysez-le à l'aide d'expressions régulières ou d'un format d'URL. Au moment de la rédaction de ce document, le format d'URL n'est pas compatible avec toutes les plates-formes.

Les stratégies les plus courantes sont les suivantes:

Mettre en cache d'abord
Recherche d'abord une réponse mise en cache, puis revient au réseau si aucune réponse n'est trouvée.
Priorité au réseau
Demande d'abord une réponse du réseau. Si aucune réponse n'est renvoyée, elle recherche la réponse dans le cache.
Obsolète lors de la revalidation
Fournit une réponse à partir du cache, tandis qu'en arrière-plan demande la dernière version et l'enregistre dans le cache pour la prochaine demande de l'élément.
Réseau uniquement
Répond toujours avec une réponse du réseau ou renvoie toujours une erreur. Le cache n'est jamais consulté.
Cache uniquement
Répond toujours par une réponse du cache ou renvoie toujours une erreur. Le réseau ne sera jamais consulté. Les éléments qui seront diffusés à l'aide de cette stratégie doivent être ajoutés au cache avant d'être demandés.

Mettre d'abord en cache

Avec cette stratégie, le service worker recherche la requête correspondante dans le cache et renvoie la réponse correspondante si elle est mise en cache. Sinon, il récupère la réponse du réseau (éventuellement, en mettant à jour le cache pour les futurs appels). En l'absence de réponse de cache ou de réseau, la requête renvoie une erreur. Étant donné que la diffusion des assets sans passer par le réseau a tendance à être plus rapide, cette stratégie donne la priorité aux performances plutôt qu'à l'actualisation.

Stratégie &quot;Cache First&quot;

self.addEventListener("fetch", event => {
   event.respondWith(
     caches.match(event.request)
     .then(cachedResponse => {
       // It can update the cache to serve updated content on the next request
         return cachedResponse || fetch(event.request);
     }
   )
  )
});

Priorité au réseau

Cette stratégie est le miroir de la stratégie Cache First. Elle vérifie si la requête peut être traitée à partir du réseau et, si ce n'est pas le cas, tente de la récupérer à partir du cache. J'aime d'abord le cache. En l'absence de réponse du réseau ou du cache, la requête renvoie une erreur. L'obtention de la réponse du réseau est généralement plus lente que celle du cache. Cette stratégie donne la priorité au contenu mis à jour plutôt qu'aux performances.

La stratégie &quot;Network First&quot;

self.addEventListener("fetch", event => {
   event.respondWith(
     fetch(event.request)
     .catch(error => {
       return caches.match(event.request) ;
     })
   );
});

Obsolète lors de la revalidation

La stratégie "obsolète lors de la revalidation" renvoie immédiatement une réponse mise en cache, puis recherche une mise à jour sur le réseau et remplace la réponse mise en cache le cas échéant. Cette stratégie envoie toujours une requête réseau, car même si une ressource mise en cache est trouvée, elle tente de mettre à jour les données du cache avec les données reçues du réseau, afin d'utiliser la version mise à jour dans la requête suivante. Cette stratégie vous permet donc de bénéficier de la diffusion rapide de la stratégie basée sur le cache et de mettre à jour le cache en arrière-plan.

La stratégie obsolète lors de la revalidation

self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request).then(cachedResponse => {
        const networkFetch = fetch(event.request).then(response => {
          // update the cache with a clone of the network response
          const responseClone = response.clone()
          caches.open(url.searchParams.get('name')).then(cache => {
            cache.put(event.request, responseClone)
          })
          return response
        }).catch(function (reason) {
          console.error('ServiceWorker fetch failed: ', reason)
        })
        // prioritize cached response over network
        return cachedResponse || networkFetch
      }
    )
  )
})

Réseau uniquement

La stratégie "Réseau uniquement" ressemble au comportement des navigateurs sans service worker ni avec l'API Cache Storage. Les requêtes ne renvoient une ressource que si elle peut être extraite du réseau. Cela est souvent utile pour des ressources telles que les requêtes API en ligne uniquement.

La stratégie &quot;Réseau uniquement&quot;

Cache uniquement

La stratégie de mise en cache uniquement garantit que les requêtes ne sont jamais transmises au réseau. Toutes les requêtes entrantes sont traitées avec un élément de cache prérempli. Le code suivant utilise le gestionnaire d'événements fetch avec la méthode match du stockage mis en cache pour répondre uniquement au cache:

self.addEventListener("fetch", event => {
   event.respondWith(caches.match(event.request));
});

Stratégie de mise en cache uniquement.

Stratégies personnalisées

Bien que les stratégies de mise en cache ci-dessus soient courantes, c'est vous qui êtes responsable de votre service worker et de la façon dont les requêtes sont traitées. Si aucune de ces options ne répond à vos besoins, créez les vôtres.

Vous pouvez, par exemple, utiliser une stratégie axée sur le réseau avec un délai d'inactivité pour donner la priorité au contenu mis à jour, mais uniquement si la réponse s'affiche en dessous d'un seuil que vous avez défini. Vous pouvez également fusionner une réponse mise en cache avec une réponse du réseau et créer une réponse complexe à partir du service worker.

Mise à jour des éléments...

Il peut s'avérer difficile de maintenir à jour les éléments mis en cache de votre PWA. Même si la stratégie obsolète de revalidation est une façon d'y parvenir, ce n'est pas la seule. Dans le chapitre Mise à jour, vous découvrirez différentes techniques pour mettre à jour le contenu et les éléments de votre application.

Ressources