Almacenamiento en caché

El almacenamiento en caché es una herramienta poderosa. Hace que las apps dependan menos de las condiciones de red. Con un buen uso de las cachés, puedes hacer que tu aplicación web esté disponible sin conexión y publicar tus recursos lo más rápido posible en cualquier condición de red. Como se mencionó en Recursos y datos, puedes decidir la mejor estrategia para almacenar en caché los recursos necesarios. Para administrar la caché, tu service worker interactúa con la API de Cache Storage.

Navegadores compatibles

  • Chrome: 43.
  • Límite: 16.
  • Firefox: 41.
  • Safari: 11.1.

Origen

La API de Cache Storage está disponible desde diferentes contextos:

  • El contexto de la ventana (el subproceso principal de tu AWP)
  • El service worker
  • Cualquier otro trabajador que uses.

Una de las ventajas de administrar la caché con service workers es que su ciclo de vida no está vinculado a la ventana, lo que significa que no se bloquea el subproceso principal. Ten en cuenta que, para usar la API de Cache Storage, la mayoría de estos contextos deben estar bajo una conexión TLS.

Qué almacenar en caché

La primera pregunta que puedes tener sobre el almacenamiento en caché es qué almacenar en caché. Si bien no hay una única respuesta para esa pregunta, puedes comenzar con todos los recursos mínimos que necesitas para renderizar la interfaz de usuario.

Entre esos recursos, se deben incluir los siguientes:

  • Es el HTML de la página principal (start_url de tu app).
  • Hojas de estilo CSS necesarias para la interfaz de usuario principal
  • Imágenes que se usan en la interfaz de usuario.
  • Archivos JavaScript necesarios para procesar la interfaz de usuario.
  • Datos, como un archivo JSON, necesarios para renderizar una experiencia básica.
  • Fuentes web
  • En una aplicación de varias páginas, otros documentos HTML que quieras publicar de forma rápida o sin conexión.

Preparado para usar sin conexión

Si bien ser compatible con el uso sin conexión es uno de los requisitos de una app web progresiva, es fundamental comprender que no todas las AWP necesitan una experiencia sin conexión completa, por ejemplo, soluciones de videojuegos en la nube o apps de criptoactivos. Por lo tanto, no hay problema en ofrecer una interfaz de usuario básica que guíe a los usuarios en esas situaciones.

Tu AWP no debe renderizar un mensaje de error de un navegador que indique que el motor de renderización web no pudo cargar la página. En su lugar, usa tu service worker para mostrar tus propios mensajes y evita que se produzca un error genérico y confuso en el navegador.

Hay muchas estrategias de almacenamiento en caché diferentes que puedes usar según las necesidades de tu AWP. Por ello, es importante diseñar el uso de la caché para proporcionar una experiencia rápida y confiable. Por ejemplo, si todos los recursos de tu aplicación se descargarán rápidamente, no consumirán mucho espacio y no es necesario actualizarlos en cada solicitud, almacenar en caché todos tus recursos sería una estrategia válida. Por otro lado, si tienes recursos que deben tener la versión más reciente, recomendamos que no almacenes esos recursos en caché.

Cómo usar la API

Usa la API de Cache Storage para definir un conjunto de cachés dentro de tu origen, cada una identificada con un nombre de cadena que puedas definir. Accede a la API a través del objeto caches; el método open permite crear o abrir una caché ya creada. El método abierto muestra una promesa para el objeto de caché.

caches.open("pwa-assets")
.then(cache => {
  // you can download and store, delete or update resources with cache arguments
});

Descarga y almacenamiento de recursos

Para pedirle al navegador que descargue y almacene los recursos, usa los métodos add o addAll. El método add realiza una solicitud y almacena una respuesta HTTP y addAll un grupo de respuestas HTTP como una transacción basada en un array de solicitudes o URLs.

caches.open("pwa-assets")
.then(cache => {
  cache.add("styles.css"); // it stores only one resource
  cache.addAll(["styles.css", "app.js"]); // it stores two resources
});

La interfaz de almacenamiento en caché almacena la totalidad de una respuesta, incluidos todos los encabezados y el cuerpo. En consecuencia, puedes recuperarlo más tarde usando una solicitud HTTP o una URL como clave. Verás cómo hacerlo en el capítulo Publicación.

Cuándo almacenar en caché

En tu AWP, eres responsable de decidir cuándo almacenar los archivos en caché. Si bien un enfoque es almacenar la mayor cantidad posible de recursos cuando se instala el service worker, no suele ser la mejor idea. Almacenar recursos innecesarios en caché desperdicia ancho de banda y espacio de almacenamiento, y podría hacer que tu app publique recursos desactualizados no deseados.

No es necesario que almacenes en caché todos los recursos a la vez, puedes almacenarlos en caché muchas veces durante el ciclo de vida de tu AWP, por ejemplo:

  • Durante la instalación del service worker
  • Después de cargar la primera página
  • Cuando el usuario navega a una sección o ruta
  • Cuando la red está inactiva.

Puedes solicitar almacenar archivos nuevos en caché en el subproceso principal o dentro del contexto del service worker.

Almacenamiento en caché de recursos en un service worker

Una de las situaciones más comunes es almacenar en caché un conjunto mínimo de recursos cuando se instala el service worker. Para ello, puedes usar la interfaz de almacenamiento en caché dentro del evento install en el service worker.

Como el subproceso del service worker se puede detener en cualquier momento, puedes solicitar al navegador que espere a que finalice la promesa addAll para aumentar las oportunidades de almacenar todos los recursos y mantener la coherencia de la app. En el siguiente ejemplo, se muestra cómo hacerlo con el método waitUntil del argumento de evento recibido en el objeto de escucha de eventos del service worker.

const urlsToCache = ["/", "app.js", "styles.css", "logo.svg"];
self.addEventListener("install", event => {
   event.waitUntil(
      caches.open("pwa-assets")
      .then(cache => {
         return cache.addAll(urlsToCache);
      });
   );
});

El método waitUntil() recibe una promesa y le pide al navegador que espere a que se resuelva la tarea de la promesa (completada o con errores) antes de finalizar el proceso del service worker. Es posible que debas encadenar promesas y mostrar las llamadas add() o addAll() para que un solo resultado llegue al método waitUntil().

También puedes controlar promesas con la sintaxis async/await. En ese caso, debes crear una función asíncrona que pueda llamar a await y que muestre una promesa a waitUntil() después de que se la llame, como en el siguiente ejemplo:

const urlsToCache = ["/", "app.js", "styles.css", "logo.svg"];
self.addEventListener("install", (event) => {
   let cacheUrls = async () => {
      const cache = await caches.open("pwa-assets");
      return cache.addAll(urlsToCache);
   };
   event.waitUntil(cacheUrls());
});

Solicitudes entre dominios y respuestas opacas

Tu AWP puede descargar y almacenar en caché recursos de tu origen y de varios dominios, como el contenido de CDN de terceros. Con una aplicación multidominio, la interacción de la caché es muy similar a las solicitudes del mismo origen. Se ejecuta la solicitud y se almacena una copia de la respuesta en la caché. Al igual que con otros elementos almacenados en caché, solo está disponible para usarse en el origen de tu app.

El recurso se almacenará como una respuesta opaca, lo que significa que tu código no podrá ver ni modificar el contenido o los encabezados de esa respuesta. Además, las respuestas opacas no exponen su tamaño real en la API de almacenamiento, lo que afecta las cuotas. Algunos navegadores exponen tamaños grandes, como 7 MB, sin importar si el archivo pesa solo 1 KB.

Actualizar y borrar recursos

Puedes actualizar los recursos con cache.put(request, response) y borrar los recursos con delete(request).

Consulta la documentación sobre objetos de la caché para obtener más detalles.

Depuración del almacenamiento en caché

Muchos navegadores ofrecen una manera de depurar el contenido del almacenamiento en caché dentro de la pestaña Application de Herramientas para desarrolladores. Allí podrás ver el contenido de cada caché dentro del origen actual. Encontrarás más información sobre estas herramientas en el capítulo Herramientas y depuración.

Las Herramientas para desarrolladores de Chrome depuran el contenido del almacenamiento en caché.

Recursos