Obtén información para usar la API de Cache y hacer que los datos de tu aplicación estén disponibles sin conexión.
La API de Cache es un sistema para almacenar y recuperar solicitudes de red y sus respuestas correspondientes. Pueden ser solicitudes y respuestas normales que se crean durante la ejecución de tu aplicación, o bien se pueden crear solo con el fin de almacenar datos para usarlos más adelante.
La API de Cache se creó para permitir que los trabajadores de servicio almacenen en caché las solicitudes de red para que puedan proporcionar respuestas rápidas, independientemente de la velocidad o la disponibilidad de la red. Sin embargo, la API también se puede usar como un mecanismo de almacenamiento general.
¿En qué dispositivos está disponible?
La API de Cache está disponible en todos los navegadores modernos. Se expone a través de la propiedad caches
global, por lo que puedes probar la presencia de la API con una detección de atributos simple:
const cacheAvailable = 'caches' in self;
Se puede acceder a la API de Cache desde una ventana, un iframe, un trabajador o un service worker.
Qué se puede almacenar
Las cachés solo almacenan pares de objetos Request
y
Response
, que representan solicitudes y respuestas HTTP,
respectivamente. Sin embargo, las solicitudes y respuestas pueden contener cualquier tipo de datos que se puedan transferir a través de HTTP.
¿Cuánto se puede almacenar?
En resumen, muchos, al menos unos doscientos megabytes y, potencialmente, cientos de gigabytes o más. Las implementaciones de navegadores varían, pero la cantidad de almacenamiento disponible suele basarse en la cantidad de almacenamiento disponible en el dispositivo.
Cómo crear y abrir una caché
Para abrir una caché, usa el método caches.open(name)
y pasa el nombre de la
caché como el único parámetro. Si la caché con nombre no existe, se creará. Este método muestra un Promise
que se resuelve con el objeto Cache
.
const cache = await caches.open('my-cache');
// do something with cache...
Cómo agregar a una caché
Existen tres formas de agregar un elemento a una caché: add
, addAll
y put
.
Los tres métodos muestran un Promise
.
cache.add
Primero, está cache.add()
. Toma un parámetro, ya sea un Request
o una URL (string
). Realiza una solicitud a la red y almacena la respuesta en la caché. Si la recuperación falla o si el código de estado de la respuesta no está en el rango 200, no se almacenará nada y se rechazará Promise
. Ten en cuenta que las solicitudes entre orígenes que no están en el modo CORS no se pueden almacenar porque muestran un status
de 0
. Estas solicitudes solo se pueden almacenar con put
.
// Retreive data.json from the server and store the response.
cache.add(new Request('/data.json'));
// Retreive data.json from the server and store the response.
cache.add('/data.json');
cache.addAll
A continuación, cache.addAll()
. Funciona de manera similar a add()
, pero toma un
arreglo de objetos Request
o URLs (string
). Esto funciona de manera similar a llamar a cache.add
para cada solicitud individual, excepto que Promise
rechaza si no se almacena en caché ninguna solicitud.
const urls = ['/weather/today.json', '/weather/tomorrow.json'];
cache.addAll(urls);
En cada uno de estos casos, una entrada nueva reemplaza cualquier entrada existente que coincida. Se usan las mismas reglas de coincidencia que se describen en la sección sobre recuperación.
cache.put
Por último, está cache.put()
, que te permite almacenar una respuesta
de la red o crear y almacenar tu propio Response
. Toma dos parámetros. El primero puede ser un objeto Request
o una URL (string
).
El segundo debe ser un Response
, ya sea de la red o generado por tu
código.
// Retrieve data.json from the server and store the response.
cache.put('/data.json');
// Create a new entry for test.json and store the newly created response.
cache.put('/test.json', new Response('{"foo": "bar"}'));
// Retrieve data.json from the 3rd party site and store the response.
cache.put('https://example.com/data.json');
El método put()
es más permisivo que add()
o addAll()
, y te permitirá almacenar respuestas que no sean de CORS, o bien otras respuestas en las que el código de estado no esté en el rango de 200. Se reemplazarán las respuestas anteriores para la misma solicitud.
Cómo crear objetos Request
Crea el objeto Request
con una URL para el elemento que se almacenará:
const request = new Request('/my-data-store/item-id');
Cómo trabajar con objetos Response
El constructor de objetos Response
acepta muchos tipos de datos, incluidos Blob
, ArrayBuffer
, objetos FormData
y cadenas.
const imageBlob = new Blob([data], {type: 'image/jpeg'});
const imageResponse = new Response(imageBlob);
const stringResponse = new Response('Hello world');
Para establecer el tipo MIME de un Response
, configura el encabezado adecuado.
const options = {
headers: {
'Content-Type': 'application/json'
}
}
const jsonResponse = new Response('{}', options);
Si recuperaste un Response
y deseas acceder a su cuerpo, hay
varios métodos auxiliares que puedes usar. Cada uno muestra un Promise
que se resuelve con un valor de un tipo diferente.
Método | Descripción |
---|---|
arrayBuffer |
Muestra un ArrayBuffer que contiene el cuerpo, serializado en bytes.
|
blob |
Muestra un objeto Blob . Si el Response se creó con un Blob , este nuevo Blob tiene el mismo tipo. De lo contrario, se usa el Content-Type de Response .
|
text |
Interpreta los bytes del cuerpo como una cadena con codificación UTF-8. |
json |
Interpreta los bytes del cuerpo como una cadena codificada en UTF-8 y, luego, intenta analizarla como JSON. Muestra el objeto resultante o arroja un TypeError si la cadena no se puede analizar como JSON.
|
formData |
Interpreta los bytes del cuerpo como un formulario HTML, codificado como multipart/form-data o application/x-www-form-urlencoded . Devuelve un objeto FormData o arroja un TypeError si no se pueden analizar los datos.
|
body |
Devuelve un ReadableStream para los datos del cuerpo. |
Por ejemplo:
const response = new Response('Hello world');
const buffer = await response.arrayBuffer();
console.log(new Uint8Array(buffer));
// Uint8Array(11) [72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]
Recuperación desde una caché
Para encontrar un elemento en una caché, puedes usar el método match
.
const response = await cache.match(request);
console.log(request, response);
Si request
es una cadena, el navegador la convierte en un Request
llamando a new Request(request)
. La función muestra un Promise
que se resuelve en un Response
si se encuentra una entrada coincidente o undefined
de lo contrario.
Para determinar si dos Requests
coinciden, el navegador usa más que solo la URL. Dos solicitudes se consideran diferentes si tienen cadenas de consulta, encabezados Vary
o métodos HTTP (GET
, POST
, PUT
, etc.) diferentes.
Puedes ignorar algunas o todas estas opciones pasando un objeto de opciones como segundo parámetro.
const options = {
ignoreSearch: true,
ignoreMethod: true,
ignoreVary: true
};
const response = await cache.match(request, options);
// do something with the response
Si más de una solicitud almacenada en caché coincide, se muestra la que se creó primero. Si deseas recuperar todas las respuestas que coincidan, puedes usar cache.matchAll()
.
const options = {
ignoreSearch: true,
ignoreMethod: true,
ignoreVary: true
};
const responses = await cache.matchAll(request, options);
console.log(`There are ${responses.length} matching responses.`);
Como atajo, puedes buscar en todas las cachés a la vez con caches.match()
en lugar de llamar a cache.match()
para cada caché.
Buscando
La API de Cache no proporciona una forma de buscar solicitudes o respuestas, excepto para las entradas que coinciden con un objeto Response
. Sin embargo, puedes implementar tu propia búsqueda mediante el filtrado o la creación de un índice.
Filtros
Una forma de implementar tu propia búsqueda es iterar sobre todas las entradas y filtrar las que deseas. Supongamos que quieres encontrar todos los elementos que tienen URLs que terminan en .png
.
async function findImages() {
// Get a list of all of the caches for this origin
const cacheNames = await caches.keys();
const result = [];
for (const name of cacheNames) {
// Open the cache
const cache = await caches.open(name);
// Get a list of entries. Each item is a Request object
for (const request of await cache.keys()) {
// If the request URL matches, add the response to the result
if (request.url.endsWith('.png')) {
result.push(await cache.match(request));
}
}
}
return result;
}
De esta manera, puedes usar cualquier propiedad de los objetos Request
y Response
para filtrar las entradas. Ten en cuenta que esto es lento si buscas en grandes conjuntos de
datos.
Cómo crear un índice
La otra forma de implementar tu propia búsqueda es mantener un índice independiente de entradas que se puedan buscar y almacenar en IndexedDB. Dado que este es el tipo de operación para la que se diseñó IndexedDB, tiene un rendimiento mucho mejor con grandes cantidades de entradas.
Si almacenas la URL de Request
junto con las propiedades que se pueden buscar, podrás recuperar fácilmente la entrada de caché correcta después de realizar la búsqueda.
Cómo borrar un elemento
Para borrar un elemento de una caché, haz lo siguiente:
cache.delete(request);
En el que la solicitud puede ser un Request
o una cadena de URL. Este método también toma el mismo objeto de opciones que cache.match
, lo que te permite borrar varios pares Request
/Response
para la misma URL.
cache.delete('/example/file.txt', {ignoreVary: true, ignoreSearch: true});
Borra una caché
Para borrar una caché, llama a caches.delete(name)
. Esta función muestra un Promise
que se resuelve en true
si la caché existía y se borró, o false
de lo contrario.
Gracias
Gracias a Mat Scales, quien escribió la versión original de este artículo, que apareció por primera vez en WebFundamentals.