Livraison

L'un des aspects clés des applications Web progressives est leur fiabilité. Elles peuvent charger rapidement des éléments, ce qui permet de maintenir l'engagement des utilisateurs et de leur fournir un retour d'information immédiat, même lorsque la connexion réseau est mauvaise. Comment est-ce possible ? Grâce à l'événement fetch du service worker.

Événement de récupération

Browser Support

  • Chrome: 40.
  • Edge: 17.
  • Firefox: 44.
  • Safari: 11.1.

Source

L'événement fetch nous permet d'intercepter chaque requête réseau effectuée par la PWA dans le champ d'application du service worker, pour les requêtes de même origine et d'origine croisée. En plus des requêtes de navigation et d'éléments, la récupération à partir d'un service worker installé permet d'afficher les visites de pages 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 permet au développeur de l'application de décider comment les traiter.

Le service worker se situe entre le client et le réseau.

Votre service worker peut transférer une requête au réseau, répondre avec une réponse précédemment mise en cache ou créer une nouvelle réponse. À vous de choisir. Prenons un exemple simple :

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

Répondre à une demande

Lorsqu'une requête arrive dans votre service worker, vous avez deux possibilités : l'ignorer, ce qui lui permet d'accéder au réseau, ou y répondre. Répondre aux requêtes depuis votre service worker vous permet de choisir ce qui est renvoyé à votre PWA et comment, même lorsque l'utilisateur est hors connexion.

Pour répondre à une requête entrante, appelez event.respondWith() à partir d'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. Toutefois, vous ne pouvez pas appeler respondWith() une fois le gestionnaire d'événements de récupération terminé, comme dans un appel asynchrone. Si vous devez attendre la réponse complète, vous pouvez transmettre une promesse à respondWith() qui se résout avec une réponse.

Créer des réponses

Grâce à l'API Fetch, vous pouvez 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 créer une réponse, créez un objet Response, en définissant son corps et ses 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, il est temps d'utiliser l'interface Caching Storage pour stocker des éléments sur l'appareil.

Vous pouvez utiliser l'API Cache Storage pour vérifier si la requête reçue de la PWA est disponible dans le cache et, si c'est le cas, y répondre avec respondWith(). 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 tous les magasins de votre origine ou sur 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

Servir des fichiers uniquement à partir du cache du navigateur ne convient pas à tous les cas d'utilisation. Par exemple, l'utilisateur ou le navigateur peuvent vider le cache. C'est pourquoi vous devez définir vos propres stratégies de diffusion des ressources pour votre PWA. Vous n'êtes pas limité à une seule stratégie de mise en cache. Vous pouvez en définir différents pour différents modèles d'URL. Par exemple, vous pouvez avoir une stratégie pour les composants d'UI minimaux, une autre pour les appels d'API et une troisième pour les URL d'images et de données. Pour ce faire, lisez 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 cet article, le format d'URL n'est pas compatible avec toutes les plates-formes.)

Voici les stratégies les plus courantes :

Cache First
Recherche d'abord une réponse mise en cache et revient au réseau si aucune n'est trouvée.
Priorité au réseau
Demande d'abord une réponse du réseau et, si aucune n'est renvoyée, vérifie si une réponse se trouve dans le cache.
Stale-While-Revalidate
Diffuser une réponse à partir du cache, tout en demandant en arrière-plan la dernière version et en l'enregistrant dans le cache pour la prochaine fois que l'élément sera demandé.
Réseau uniquement
 répond toujours avec une réponse du réseau ou une erreur. Le cache n'est jamais consulté.
Cache uniquement
 Répond toujours avec une réponse du cache ou génère une erreur. Le réseau ne sera jamais consulté. Les composants qui seront diffusés à l'aide de cette stratégie doivent être ajoutés au cache avant d'être demandés.

Cache first

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 (en mettant éventuellement à jour le cache pour les futurs appels). Si la requête ne reçoit ni réponse du cache ni réponse du réseau, elle génère une erreur. Étant donné que la diffusion d'éléments sans passer par le réseau est généralement plus rapide, cette stratégie privilégie les performances à la fraîcheur.

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);
     }
   )
  )
});

Réseau en premier

Cette stratégie est l'inverse de la stratégie "Cache First". Elle vérifie si la requête peut être satisfaite à partir du réseau et, si ce n'est pas le cas, tente de la récupérer à partir du cache. Comme "cache first". Si aucune réponse réseau ni aucune réponse de cache n'est disponible, la requête générera une erreur. L'obtention de la réponse à partir du réseau est généralement plus lente que celle à partir du cache. Cette stratégie privilégie le contenu mis à jour plutôt que les performances.

Stratégie Network First

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

Obsolète pendant la revalidation

La stratégie "Obsolète pendant la revalidation" renvoie immédiatement une réponse mise en cache, puis vérifie si une mise à jour est disponible sur le réseau. Si c'est le cas, elle remplace la réponse mise en cache. Cette stratégie effectue toujours une requête réseau, car même si une ressource mise en cache est trouvée, elle tentera de mettre à jour le contenu du cache avec ce qui a été reçu du réseau, afin d'utiliser la version mise à jour lors de la prochaine requête. Cette stratégie vous permet donc de bénéficier de la diffusion rapide de la stratégie "Cache first" et de mettre à jour le cache en arrière-plan.

Stratégie &quot;Obsolète pendant la revalidation&quot;

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" est semblable au comportement des navigateurs sans service worker ni API Cache Storage. Les requêtes ne renvoient une ressource que si elle peut être récupérée à partir du réseau. Cela est souvent utile pour les ressources telles que les requêtes d'API en ligne uniquement.

Stratégie &quot;Réseau uniquement&quot;

Cache uniquement

La stratégie de cache uniquement garantit que les requêtes ne sont jamais envoyées 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 du cache pour répondre au cache uniquement :

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

Stratégie de cache uniquement.

Stratégies personnalisées

Bien que les stratégies de mise en cache ci-dessus soient courantes, vous êtes responsable de votre service worker et de la manière dont les requêtes sont traitées. Si aucune de ces options ne répond à vos besoins, créez la vôtre.

Par exemple, vous pouvez utiliser une stratégie "network first" avec un délai d'attente pour donner la priorité au contenu mis à jour, mais uniquement si la réponse apparaît dans un seuil que vous avez défini. Vous pouvez également fusionner une réponse mise en cache avec une réponse réseau et créer une réponse complexe à partir du service worker.

Mettre à jour les composants

Il peut être difficile de maintenir à jour les ressources mises en cache de votre PWA. Bien que la stratégie "Périmé pendant la revalidation" soit une façon de procéder, ce n'est pas la seule. Dans le chapitre sur la mise à jour, vous découvrirez différentes techniques pour maintenir à jour le contenu et les ressources de votre application.

Ressources