Actualiser les résultats avec des ressources "stale-while-revalidate"

Outil supplémentaire pour vous aider à équilibrer l'immédiateté et la fraîcheur lorsque vous diffusez votre application Web.

stale-while-revalidate aide les développeurs à trouver un équilibre entre l'immédiateté (chargement immédiat du contenu mis en cache) et la fraîcheur (assurance que les mises à jour du contenu mis en cache seront utilisées à l'avenir). Si vous gérez un service Web ou une bibliothèque tiers qui est mis à jour régulièrement, ou si vos composants first party ont tendance à avoir une durée de vie courte, stale-while-revalidate peut être un ajout utile à vos règles de mise en cache existantes.

La prise en charge de la définition de stale-while-revalidate avec max-age dans l'en-tête de réponse Cache-Control est disponible dans Chrome 75 et Firefox 68.

Les navigateurs qui ne prennent pas en charge stale-while-revalidate ignorent cette valeur de configuration de manière silencieuse et utilisent max-age, comme je vais l'expliquer sous peu.

Qu'est-ce que cela signifie ?

Décomposons stale-while-revalidate en deux parties: l'idée qu'une réponse mise en cache peut être obsolète et le processus de revalidation.

Tout d'abord, comment le navigateur sait-il si une réponse mise en cache est "obsolète" ? Un en-tête de réponse Cache-Control contenant stale-while-revalidate doit également contenir max-age. Le nombre de secondes spécifié via max-age détermine l'obsolescence. Toute réponse mise en cache plus récente que max-age est considérée comme à jour, et les réponses mises en cache plus anciennes sont obsolètes.

Si la réponse mise en cache localement est toujours récente, elle peut être utilisée telle quelle pour répondre à la requête d'un navigateur. Du point de vue de stale-while-revalidate, aucune action n'est requise dans ce scénario.

Toutefois, si la réponse mise en cache est obsolète, une autre vérification basée sur l'âge est effectuée : l'âge de la réponse mise en cache se situe-t-il dans la période supplémentaire fournie par le paramètre stale-while-revalidate ?

Si l'âge d'une réponse obsolète se situe dans cette période, elle sera utilisée pour répondre à la requête du navigateur. En même temps, une requête de "révalidation" sera envoyée au réseau de manière à ne pas retarder l'utilisation de la réponse mise en cache. La réponse renvoyée peut contenir les mêmes informations que la réponse précédemment mise en cache, ou elle peut être différente. Dans tous les cas, la réponse réseau est stockée localement, remplaçant ce qui était auparavant mis en cache et réinitialisant le minuteur de "fraîcheur" utilisé lors de toute future comparaison max-age.

Toutefois, si la réponse mise en cache obsolète est suffisamment ancienne pour qu'elle ne se situe pas dans la période stale-while-revalidate, elle ne répondra pas à la requête du navigateur. Le navigateur récupère plutôt une réponse du réseau et l'utilise à la fois pour répondre à la requête initiale et pour remplir le cache local avec une nouvelle réponse.

Exemple réel

Vous trouverez ci-dessous un exemple simple d'API HTTP permettant de renvoyer l'heure actuelle, plus précisément le nombre actuel de minutes après l'heure.

Dans ce scénario, le serveur Web utilise cet en-tête Cache-Control dans sa réponse HTTP:

Cache-Control: max-age=1, stale-while-revalidate=59

Ce paramètre signifie que si une requête de l'heure est répétée dans la seconde qui suit, la valeur précédemment mise en cache sera toujours à jour et utilisée telle quelle, sans aucune revalidation.

Si une requête est répétée entre 1 et 60 secondes plus tard, la valeur mise en cache sera obsolète, mais elle sera utilisée pour répondre à la requête API. En même temps, "en arrière-plan", une requête de revalidation sera envoyée pour renseigner le cache avec une valeur actualisée à utiliser ultérieurement.

Si une requête est répétée au bout de plus de 60 secondes, la réponse obsolète n'est pas utilisée du tout. La réponse à la requête du navigateur et la revalidation du cache dépendent toutes deux de la réception d'une réponse du réseau.

Voici un récapitulatif de ces trois états distincts, ainsi que la période à laquelle chacun d'eux s'applique pour notre exemple:

Schéma illustrant les informations de la section précédente.

Quels sont les cas d'utilisation courants ?

Bien que l'exemple ci-dessus d'un service d'API "minutes après l'heure" soit artificiel, il illustre le cas d'utilisation attendu : des services qui fournissent des informations qui doivent être actualisées, mais pour lesquels un certain degré d'obsolescence est acceptable.

Des exemples moins artificiels peuvent être une API pour les conditions météorologiques actuelles ou les titres d'actualités les plus populaires publiés au cours de la dernière heure.

En règle générale, toute réponse qui est mise à jour à un intervalle connu, est susceptible d'être demandée plusieurs fois et est statique dans cet intervalle est un bon candidat pour le stockage en cache à court terme via max-age. L'utilisation de stale-while-revalidate en plus de max-age augmente la probabilité que les futures requêtes puissent être satisfaites à partir du cache avec du contenu plus récent, sans blocage sur une réponse réseau.

Comment interagit-il avec les service workers ?

Si vous avez entendu parler de stale-while-revalidate, il est probable que ce soit dans le contexte des recettes utilisées dans un service worker.

L'utilisation de "stale-while-revalidate" via un en-tête Cache-Control présente certaines similitudes avec son utilisation dans un service worker, et de nombreuses considérations similaires concernant les compromis de fraîcheur et les durées de vie maximales s'appliquent. Toutefois, vous devez prendre en compte certains éléments lorsque vous décidez d'implémenter une approche basée sur un service worker ou de vous appuyer simplement sur la configuration de l'en-tête Cache-Control.

Utilisez une approche de service worker si :

  • Vous utilisez déjà un service worker dans votre application Web.
  • Vous avez besoin d'un contrôle précis sur le contenu de vos caches et vous souhaitez implémenter une stratégie d'expiration de l'élément le moins utilisé. Le module Expiration du cache de Workbox peut vous aider.
  • Vous souhaitez être informé lorsqu'une réponse obsolète change en arrière-plan lors de l'étape de revalidation. Le module Broadcast Cache Update de Workbox peut vous aider.
  • Vous avez besoin de ce comportement stale-while-revalidate dans tous les navigateurs modernes.

Utilisez une approche Cache-Control dans les cas suivants :

  • Vous préférez ne pas avoir à gérer les coûts liés au déploiement et à la maintenance d'un service worker pour votre application Web.
  • Vous acceptez que la gestion automatique du cache du navigateur empêche vos caches locaux de devenir trop volumineux.
  • Vous acceptez une approche qui n'est actuellement pas compatible avec tous les navigateurs modernes (en date de juillet 2019, la compatibilité peut s'étendre à l'avenir).

Si vous utilisez un service worker et que stale-while-revalidate est également activé pour certaines réponses via un en-tête Cache-Control, le service worker aura généralement la priorité pour répondre à une requête. Si le service worker décide de ne pas répondre ou s'il effectue une requête réseau à l'aide de fetch() lors de la génération d'une réponse, le comportement configuré via l'en-tête Cache-Control sera appliqué.

En savoir plus

Image principale par Samuel Zeller.