Livraison

L'un des principaux aspects des applications Web progressives est qu'elles sont fiables. Elles peuvent charger des éléments rapidement, ce qui permet de maintenir l'engagement des utilisateurs et de fournir des commentaires immédiats, 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 d'origine et les requêtes inter-origines. En plus des requêtes de navigation et d'éléments, l'extraction à 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 requête

Lorsqu'une requête arrive dans votre service worker, vous avez deux possibilités : l'ignorer, ce qui lui permet d'être transmise au réseau, ou y répondre. En répondant aux requêtes à partir de votre service worker, vous pouvez 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 suit:

// 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 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 diffuser des réponses HTTP à partir d'un service worker, il est temps d'utiliser l'interface de stockage en cache pour stocker des éléments sur l'appareil.

Vous pouvez utiliser l'API de stockage de cache pour vérifier si la requête reçue de la PWA est disponible dans le cache. Si c'est le cas, répondez à 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 niveau supérieur, 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 peuvent vider le cache. C'est pourquoi vous devez définir vos propres stratégies de diffusion d'assets 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 formats 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, 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.)

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 n'est trouvée.
Réseau en premier
Demande d'abord une réponse au réseau et, si aucune n'est renvoyée, recherche une réponse dans le cache.
Obsolète lors de la revalidation
Diffuse 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'asset sera demandé.
Réseau uniquement
Renvoie toujours une réponse du réseau ou génère 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.

Mettre en cache d'abord

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 option, en mettant à jour le cache pour les futurs appels). Si aucune réponse de cache ni de réseau n'est renvoyée, la requête échoue. Étant donné que la diffusion d'éléments sans passer par le réseau est généralement plus rapide, cette stratégie donne la priorité aux performances par rapport à 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 priorité

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 le cache d'abord. Si aucune réponse réseau ni aucune réponse du cache n'est renvoyée, la requête échoue. 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.

Stratégie axée sur le réseau

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 validation" 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 si une mise à jour est détectée. Cette stratégie effectue toujours une requête réseau, car même si une ressource mise en cache est détectée, elle tente de mettre à jour ce qui était dans le cache avec ce qui a été reçu du réseau, afin d'utiliser la version mise à jour dans la requête suivante. Cette stratégie vous permet donc de profiter du service rapide de la stratégie "cache first" et de mettre à jour le cache en arrière-plan.

Stratégie d&#39;obsolescence 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 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 sur le 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 par un élément de cache prérempli. Le code suivant utilise le gestionnaire d'événements fetch avec la méthode match du stockage 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, vous êtes responsable de votre service worker et de la manière dont les requêtes sont gérées. Si aucune de ces options ne répond à vos besoins, créez-en une.

Vous pouvez, par exemple, utiliser une stratégie de priorité au réseau avec un délai avant expiration pour donner la priorité aux contenus mis à jour, mais uniquement si la réponse apparaît dans un délai que vous définissez. 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 des composants

Il peut s'avérer difficile de maintenir à jour les éléments mis en cache de votre PWA. La stratégie "obsolète lors de la validation" est un moyen d'y parvenir, mais ce n'est pas le seul. Dans le chapitre "Mise à jour", vous découvrirez différentes techniques pour mettre à jour le contenu et les éléments de votre application.

Ressources