Jusqu'à présent, il n'y avait que des mentions et de minuscules extraits de code
Interface Cache
.
Pour utiliser efficacement les service workers, il faut adopter une ou plusieurs stratégies de mise en cache,
ce qui nécessite quelques connaissances sur l'interface Cache
.
Une stratégie de mise en cache est une interaction entre l'événement fetch
d'un service worker et l'interface Cache
.
La façon dont une stratégie de mise en cache est écrite dépend
par exemple, il peut être préférable de gérer les requêtes d'éléments statiques différemment des demandes de documents,
et cela affecte la composition d'une stratégie de mise en cache.
Avant d'aborder les stratégies,
Prenons une seconde pour découvrir ce qu'est l'interface Cache
, ce qu'elle est.
et un aperçu de certaines des méthodes qu'il propose
pour gérer les caches de service workers.
Comparaison entre l'interface Cache
et le cache HTTP
Si vous n'avez jamais travaillé avec l'interface Cache
auparavant,
il pourrait être tentant de le considérer
comme la même chose que :
ou du moins au cache HTTP. Ce n'est pas le cas.
- L'interface
Cache
est un mécanisme de mise en cache entièrement distinct du cache HTTP. - Quel que soit
Cache-Control
que vous utilisez pour influencer le cache HTTP n'a aucune incidence sur les éléments stockés dans l'interfaceCache
.
Il est utile de considérer les caches des navigateurs comme des couches. Le cache HTTP est un cache de bas niveau alimenté par des paires clé-valeur avec des instructions exprimées dans des en-têtes HTTP.
En revanche, l'interface Cache
est un cache de haut niveau géré par une API JavaScript.
Cela offre plus de flexibilité que lorsque vous utilisez des paires clé-valeur HTTP relativement simplistes,
et c'est la moitié de ce qui rend
les stratégies de mise en cache possibles.
Voici quelques méthodes d'API importantes concernant les caches de service workers:
CacheStorage.open
pour créer une instanceCache
.Cache.add
etCache.put
pour stocker les réponses du réseau dans un cache de service worker.Cache.match
pour localiser une réponse mise en cache dans une instanceCache
.Cache.delete
pour supprimer une réponse mise en cache d'une instanceCache
.
En voici quelques-uns. Il existe d'autres méthodes utiles, mais ce sont les fonctions de base que vous verrez utilisées plus loin dans ce guide.
L'événement fetch
modeste
L'autre moitié d'une stratégie de mise en cache est l'authentification
Événement fetch
.
Jusqu'à présent, dans cette documentation, vous avez
un peu entendu parler de l'« interception des requêtes réseau »,
et l'événement fetch
dans un service worker est l'endroit où cela se produit:
// Establish a cache name
const cacheName = 'MyFancyCacheName_v1';
self.addEventListener('install', (event) => {
event.waitUntil(caches.open(cacheName));
});
self.addEventListener('fetch', async (event) => {
// Is this a request for an image?
if (event.request.destination === 'image') {
// Open the cache
event.respondWith(caches.open(cacheName).then((cache) => {
// Respond with the image from the cache or from the network
return cache.match(event.request).then((cachedResponse) => {
return cachedResponse || fetch(event.request.url).then((fetchedResponse) => {
// Add the network response to the cache for future visits.
// Note: we need to make a copy of the response to save it in
// the cache and use the original as the request response.
cache.put(event.request, fetchedResponse.clone());
// Return the network response
return fetchedResponse;
});
});
}));
} else {
return;
}
});
Voici un exemple de jouet, et que vous pouvez constater par vous-même, elle offre un aperçu de ce que les service workers peuvent faire. Le code ci-dessus effectue les opérations suivantes:
- Inspectez la propriété
destination
de la requête pour voir s'il s'agit d'une requête d'image. - Si l'image se trouve dans le cache du service worker, diffusez-la à partir de cet emplacement. Sinon, récupérez l'image sur le réseau, stocker la réponse dans le cache et renvoyer la réponse du réseau.
- Toutes les autres requêtes sont transmises par le service worker sans interaction avec le cache.
L'objet event
d'une extraction contient
Propriété request
quelques informations utiles pour vous aider à identifier le type de chaque requête:
url
, qui est l'URL de la requête réseau actuellement gérée par l'événementfetch
.method
, qui est la méthode de requête (par exemple,GET
ouPOST
).mode
, qui décrit le mode de la requête. La valeur'navigate'
est souvent utilisée pour distinguer les demandes de documents HTML des autres demandes.destination
, qui décrit le type de contenu demandé sans utiliser l'extension de fichier de l'élément demandé.
Encore une fois, le nom du jeu est asynchrone.
Rappelez-vous que l'événement install
propose une
event.waitUntil
qui reçoit une promesse et attend sa résolution avant de passer à l'activation.
L'événement fetch
offre une fonctionnalité
Méthode event.respondWith
que vous pouvez utiliser pour renvoyer le résultat d'une requête
Demande fetch
ou une réponse renvoyée par l'interface Cache
méthode match
.
Stratégies de mise en cache
Maintenant que vous vous êtes familiarisé avec les instances Cache
et le gestionnaire d'événements fetch
,
vous êtes prêt à vous plonger dans les stratégies
de mise en cache des service workers.
Bien que les possibilités soient
pratiquement infinies,
Ce guide s'appuiera sur les stratégies fournies avec Workbox,
afin que vous puissiez avoir une idée de ce
qui se passe dans les composants internes de Workbox.
Cache uniquement
Commençons par une stratégie simple de mise en cache que nous appellerons "Cache uniquement". C'est simple: quand le service worker contrôle la page, les requêtes correspondantes ne seront que transmises au cache. Cela signifie que tous les éléments mis en cache devront être mis en pré-cache pour que le format fonctionne. et que ces éléments ne seront jamais mis à jour dans le cache tant que le service worker n'aura pas été mis à jour.
// Establish a cache name
const cacheName = 'MyFancyCacheName_v1';
// Assets to precache
const precachedAssets = [
'/possum1.jpg',
'/possum2.jpg',
'/possum3.jpg',
'/possum4.jpg'
];
self.addEventListener('install', (event) => {
// Precache assets on install
event.waitUntil(caches.open(cacheName).then((cache) => {
return cache.addAll(precachedAssets);
}));
});
self.addEventListener('fetch', (event) => {
// Is this one of our precached assets?
const url = new URL(event.request.url);
const isPrecachedRequest = precachedAssets.includes(url.pathname);
if (isPrecachedRequest) {
// Grab the precached asset from the cache
event.respondWith(caches.open(cacheName).then((cache) => {
return cache.match(event.request.url);
}));
} else {
// Go to the network
return;
}
});
Ci-dessus, un tableau d'éléments est mis en pré-cache au moment de l'installation.
Lorsque le service worker traite les récupérations,
nous vérifions si l'URL de requête gérée par l'événement fetch
se trouve dans le tableau d'éléments mis en pré-cache.
Si tel est le cas, nous récupérons la ressource dans le cache et ignorons le réseau.
Les autres requêtes passent par le réseau,
et uniquement le réseau.
Pour voir cette stratégie
en action,
Regardez cette démonstration avec la console ouverte.
Réseau uniquement
Le contraire de "Cache uniquement" est "Réseau uniquement", où une requête est transmise au réseau par un service worker sans interaction avec le cache du service worker. Il s'agit d'une bonne stratégie pour garantir l'actualisation du contenu (balisage, par exemple). mais en contrepartie, cela ne fonctionnera jamais lorsque l'utilisateur est hors connexion.
S'assurer qu'une requête est transmise au réseau signifie simplement que vous n'appelez pas event.respondWith
pour une requête de mise en correspondance.
Si vous voulez
être explicite,
vous pouvez ajouter un return;
vide dans votre rappel d'événement fetch
pour les requêtes que vous souhaitez transmettre au réseau.
Voici ce qu'il se passe dans le mode "Cache uniquement" : pour les requêtes qui ne sont pas mises en pré-cache.
Mettre en cache d'abord, en revenant au réseau
Avec cette stratégie, les choses deviennent un peu plus complexes. Pour les requêtes correspondantes, le processus est le suivant:
- La requête est mise en cache. Si l'élément se trouve dans le cache, diffusez-le à partir de là.
- Si la requête ne se trouve pas dans le cache, accédez au réseau.
- Une fois la requête réseau terminée, ajoutez-la au cache, puis renvoie la réponse à partir du réseau.
Voici un exemple de cette stratégie, que vous pouvez tester Une démonstration en direct:
// Establish a cache name
const cacheName = 'MyFancyCacheName_v1';
self.addEventListener('fetch', (event) => {
// Check if this is a request for an image
if (event.request.destination === 'image') {
event.respondWith(caches.open(cacheName).then((cache) => {
// Go to the cache first
return cache.match(event.request.url).then((cachedResponse) => {
// Return a cached response if we have one
if (cachedResponse) {
return cachedResponse;
}
// Otherwise, hit the network
return fetch(event.request).then((fetchedResponse) => {
// Add the network response to the cache for later visits
cache.put(event.request, fetchedResponse.clone());
// Return the network response
return fetchedResponse;
});
});
}));
} else {
return;
}
});
Bien que cet exemple ne concerne que les images, cette stratégie est efficace à appliquer à tous les éléments statiques (CSS, JavaScript, images et polices), en particulier ceux dont la version est hachée. Elle accélère les composants immuables en ignorant toute vérification d'actualisation du contenu auprès du serveur que le cache HTTP peut lancer. Plus important encore, tous les éléments mis en cache seront disponibles hors connexion.
Premièrement, le réseau, en revenant au cache
Si vous deviez inverser « Le cache d'abord, puis le réseau » sur sa tête, on obtient le type "Réseau d'abord, deuxième cache" comme vous le voyez:
- Vous accédez d'abord au réseau pour une requête, puis vous placez la réponse dans le cache.
- Si vous êtes hors connexion par la suite, vous revenez à la dernière version de cette réponse dans le cache.
Cette stratégie est idéale pour les requêtes HTML ou API en ligne, vous voulez connaître la version la plus récente d'une ressource, mais souhaitez accorder un accès hors connexion à la version la plus récente disponible. Voici ce à quoi cela pourrait ressembler lorsqu'il est appliqué à des demandes pour HTML:
// Establish a cache name
const cacheName = 'MyFancyCacheName_v1';
self.addEventListener('fetch', (event) => {
// Check if this is a navigation request
if (event.request.mode === 'navigate') {
// Open the cache
event.respondWith(caches.open(cacheName).then((cache) => {
// Go to the network first
return fetch(event.request.url).then((fetchedResponse) => {
cache.put(event.request, fetchedResponse.clone());
return fetchedResponse;
}).catch(() => {
// If the network is unavailable, get
return cache.match(event.request.url);
});
}));
} else {
return;
}
});
Vous pouvez essayer cette fonctionnalité lors d'une démonstration. Tout d'abord, accédez à la page. Vous devrez peut-être actualiser la page avant de placer la réponse HTML dans le cache. Ensuite, dans les outils pour les développeurs, simuler une connexion hors connexion ; et actualisez-le de nouveau. La dernière version disponible sera diffusée instantanément à partir du cache.
Dans les cas où la capacité hors connexion est importante, mais vous devez trouver un équilibre entre ces capacités et l'accès à la version la plus récente d'un élément de balisage ou de données d'API. "Le réseau d'abord, puis le cache" est une stratégie solide qui permet d'atteindre cet objectif.
Obsolète pendant la revalidation
Parmi les stratégies évoquées jusqu'à présent, est le plus complexe. Elle est similaire aux deux dernières stratégies d’une certaine manière, mais la procédure donne la priorité à la vitesse d'accès à une ressource, tout en les maintenant à jour en arrière-plan. Cette stratégie ressemble à ceci:
- Lors de la première demande d'élément, récupérez-le sur le réseau, le placer dans le cache et renvoyer la réponse du réseau.
- Lors des requêtes suivantes, diffusez d'abord l'élément à partir du cache, puis "en arrière-plan". redemander l'élément sur le réseau et mettre à jour l'entrée de cache de l'élément.
- Pour les requêtes ultérieures, vous recevrez la dernière version extraite du réseau, qui a été placée dans le cache lors de l'étape précédente.
C'est une excellente stratégie pour les mises à jour qu'il est important de garder à jour, mais elles ne sont pas cruciales. Pensez à des choses comme des avatars pour un site de médias sociaux. Elles sont mises à jour lorsque les utilisateurs se déplacent, mais la dernière version n'est pas strictement nécessaire à chaque demande.
// Establish a cache name
const cacheName = 'MyFancyCacheName_v1';
self.addEventListener('fetch', (event) => {
if (event.request.destination === 'image') {
event.respondWith(caches.open(cacheName).then((cache) => {
return cache.match(event.request).then((cachedResponse) => {
const fetchedResponse = fetch(event.request).then((networkResponse) => {
cache.put(event.request, networkResponse.clone());
return networkResponse;
});
return cachedResponse || fetchedResponse;
});
}));
} else {
return;
}
});
Vous pouvez voir
cela en action dans
mais une autre démonstration en direct,
en particulier si vous regardez l'onglet "Réseau"
dans les outils pour les développeurs de votre navigateur,
et sa visionneuse CacheStorage
(si les outils pour les développeurs de votre navigateur en proposent un tel outil).
En avant vers Workbox !
Ce document conclut notre examen de l'API Service Worker, ainsi que les API associées, Vous en savez donc suffisamment sur l'utilisation directe des service workers pour commencer à bricoler avec Workbox.