Almacenamiento en caché

El almacenamiento en caché es una herramienta potente. Hace que tus apps sean menos dependientes de las condiciones de red. Si usas correctamente las cachés, puedes hacer que tu app web esté disponible sin conexión y entregar tus recursos lo más rápido posible en cualquier condición de red. Como se menciona 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.
  • Edge: 16.
  • Firefox: 41.
  • Safari: 11.1.

Origen

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

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

Una ventaja de administrar la caché con los trabajadores del servicio es que su ciclo de vida no está vinculado a la ventana, lo que significa que no estás bloqueando 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 podrías tener sobre el almacenamiento en caché es qué almacenar en caché. Si bien no hay una sola respuesta a esa pregunta, puedes comenzar con todos los recursos mínimos que necesitas para renderizar la interfaz de usuario.

Esos recursos deben incluir lo siguiente:

  • El código HTML de la página principal (la URL de inicio de tu app)
  • Hojas de estilo CSS necesarias para la interfaz de usuario principal.
  • Imágenes que se usan en la interfaz de usuario.
  • Son archivos JavaScript necesarios para renderizar 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 deseas entregar rápidamente o sin conexión

Listo para el uso sin conexión

Si bien ser compatible con el modo 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, las soluciones de juegos en la nube o las apps de activos criptográficos. Por lo tanto, está bien 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 del navegador que indique que el motor de renderización web no pudo cargar la página. En su lugar, usa tu trabajador de servicio para mostrar tus propios mensajes y evitar un error genérico y confuso del navegador.

Existen muchas estrategias de almacenamiento en caché diferentes que puedes usar según las necesidades de tu AWP. Por eso, 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 app se descargan rápido, no consumen mucho espacio y no necesitan actualizarse en cada solicitud, almacenar en caché todos tus recursos sería una estrategia válida. Por otro lado, si tienes recursos que deben ser la versión más reciente, te recomendamos que no almacenes en caché esos recursos.

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 puedes definir. Accede a la API a través del objeto caches, y el método open habilita la creación o apertura de una caché ya creada. El método open 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 almacena 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 toda una respuesta, incluidos todos los encabezados y el cuerpo. Por lo tanto, puedes recuperarla más adelante con 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, tú eres responsable de decidir cuándo almacenar archivos en caché. Si bien un enfoque es almacenar tantos recursos como sea posible cuando se instala el trabajador de servicio, por lo general, no es la mejor idea. La caché de recursos innecesarios 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 almacenar en caché recursos muchas veces durante el ciclo de vida de tu AWP, por ejemplo:

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

Puedes solicitar la caché de archivos nuevos 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 trabajador del servicio. Para ello, puedes usar la interfaz de almacenamiento en caché dentro del evento install en el trabajador de servicio.

Como el subproceso del trabajador de servicio se puede detener en cualquier momento, puedes solicitarle al navegador que espere a que finalice la promesa de addAll para aumentar la oportunidad 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 del evento recibido en el objeto de escucha de eventos del trabajador de servicio.

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 en la promesa (se cumpla o falle) antes de finalizar el proceso del trabajador de servicio. 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 devuelva 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 app 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 recursos 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 ni 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 es de solo 1 KB.

Actualiza y borra recursos

Puedes actualizar los activos con cache.put(request, response) y borrarlos con delete(request).

Consulta la documentación del objeto de caché para obtener más detalles.

Cómo depurar el almacenamiento en caché

Muchos navegadores ofrecen una forma de depurar el contenido del almacenamiento en caché en la pestaña Aplicación de DevTools. Allí, puedes ver el contenido de cada caché dentro del origen actual. Hablaremos más sobre estas herramientas en el capítulo Herramientas y depuración.

Depuración del contenido del almacenamiento en caché con las Herramientas para desarrolladores de Chrome

Recursos