Complementa las técnicas tradicionales de precarga con trabajadores del servicio.
Por lo general, realizar una tarea en un sitio implica varios pasos. Por ejemplo, comprar un producto en un sitio web de comercio electrónico podría implicar buscar un producto, elegir un artículo de la lista de resultados, agregar el artículo al carrito y completar la operación de pago.
En términos técnicos, desplazarse por diferentes páginas significa realizar una solicitud de navegación. Como regla general, no debes usar encabezados Cache-Control
de larga duración para almacenar en caché la respuesta HTML de una solicitud de navegación. Por lo general, se deben satisfacer a través de la red, con Cache-Control: no-cache
, para garantizar que el HTML, junto con la cadena de solicitudes de red posteriores, esté (razonablemente) actualizado.
Lamentablemente, tener que ir contra la red cada vez que el usuario navega a una página nueva significa que cada navegación puede ser lenta, al menos significa que no será confiable rápida.
Para acelerar estas solicitudes, si puedes anticipar la acción del usuario, puedes solicitar estas páginas y recursos con anticipación y mantenerlos en la caché durante un período breve hasta que el usuario haga clic en estos vínculos. Esta técnica se denomina precarga y, por lo general, se implementa agregando etiquetas <link rel="prefetch">
a las páginas, lo que indica el recurso que se debe precargar.
En esta guía, exploraremos diferentes maneras en las que se pueden usar los service workers como un complemento de las técnicas tradicionales de carga previa.
Casos de producción
MercadoLibre es el sitio de comercio electrónico más grande de Latinoamérica. Para acelerar las navegaciones, inyectan etiquetas <link rel="prefetch">
de forma dinámica en algunas partes del flujo. Por ejemplo, en las páginas de fichas, recuperan la página de resultados siguiente en cuanto el usuario se desplaza hasta la parte inferior de la ficha:
Los archivos almacenados previamente se solicitan con la prioridad "Más baja" y se almacenan en la caché HTTP o en la caché de memoria (según si el recurso se puede almacenar en caché o no) durante un período que varía según el navegador. Por ejemplo, a partir de Chrome 85, este valor es de 5 minutos. Los recursos se conservan durante cinco minutos, después de los cuales se aplican las reglas normales de Cache-Control
para el recurso.
Usar el almacenamiento en caché del service worker puede ayudarte a extender la vida útil de los recursos de carga previa más allá del período de cinco minutos.
Por ejemplo, el portal deportivo italiano Virgilio Sport usa trabajadores del servicio para obtener la carga previa de las publicaciones más populares en su página principal. También usan la API de Network Information para evitar la carga previa para los usuarios que tienen una conexión 2G.
Como resultado, durante 3 semanas de observación, Virgilio Sport observó que los tiempos de carga de la navegación a los artículos mejoraron un 78% y la cantidad de impresiones de artículos aumentó en un 45%.
Implementa el almacenamiento en caché previo con Workbox
En la siguiente sección, usaremos Workbox para mostrar cómo implementar diferentes técnicas de almacenamiento en caché en el service worker, que se pueden usar como complemento de <link rel="prefetch">
, o incluso como reemplazo, delegando esta tarea por completo al service worker.
1. Almacena previamente en caché páginas estáticas y subrecursos de página
El almacenamiento previo en caché es la capacidad del service worker de guardar archivos en la caché mientras se instala.
En los siguientes casos, el almacenamiento previo en caché se usa para lograr un objetivo similar al de la carga previa: acelerar las navegaciones.
Almacenamiento previo en caché de páginas estáticas
En el caso de las páginas que se generan en el tiempo de compilación (p. ej., about.html
, contact.html
) o en sitios completamente estáticos, solo se pueden agregar los documentos del sitio a la lista de almacenamiento en caché previo, de modo que ya estén disponibles en la caché cada vez que el usuario acceda a ellos:
workbox.precaching.precacheAndRoute([
{url: '/about.html', revision: 'abcd1234'},
// ... other entries ...
]);
Almacenamiento en caché de subrecursos de página
Una práctica recomendada general es almacenar en caché previamente los recursos estáticos que podrían usar las diferentes secciones del sitio (p. ej., JavaScript, CSS, etc.) y puede proporcionar un impulso adicional en las situaciones de almacenamiento en caché previo.
Para acelerar la navegación en un sitio de comercio electrónico, puedes usar etiquetas <link rel="prefetch">
en las páginas de fichas para recuperar previamente las páginas de detalles de los primeros productos de una página de ficha. Si ya almacenaste en caché los subrecursos de la página del producto, la navegación puede ser aún más rápida.
Para implementar esta función, sigue estos pasos:
- Agrega una etiqueta
<link rel="prefetch">
a la página:
<link rel="prefetch" href="/phones/smartphone-5x.html" as="document">
- Agrega los subrecursos de la página a la lista de caché previa en el service worker:
workbox.precaching.precacheAndRoute([
'/styles/product-page.ac29.css',
// ... other entries ...
]);
2. Extiende la vida útil de los recursos de precarga
Como se mencionó antes, <link rel="prefetch">
recupera y mantiene los recursos en la caché HTTP durante un período limitado. Después de ese período, se aplican las reglas Cache-Control
para un recurso. A partir de Chrome 85, este valor es de 5 minutos.
Los trabajadores de servicio te permiten extender la vida útil de las páginas de precarga y, al mismo tiempo, ofrecen el beneficio adicional de que esos recursos estén disponibles para el uso sin conexión.
En el ejemplo anterior, se podría complementar el <link rel="prefetch">
que se usa para recuperar previamente una página de producto con una estrategia de almacenamiento en caché del entorno de ejecución de Workbox.
Para implementarlo, sigue estos pasos:
- Agrega una etiqueta
<link rel="prefetch">
a la página:
<link rel="prefetch" href="/phones/smartphone-5x.html" as="document">
- Implementa una estrategia de almacenamiento en caché en tiempo de ejecución en el service worker para los siguientes tipos de solicitudes:
new workbox.strategies.StaleWhileRevalidate({
cacheName: 'document-cache',
plugins: [
new workbox.expiration.Plugin({
maxAgeSeconds: 30 * 24 * 60 * 60, // 30 Days
}),
],
});
En este caso, hemos optado por usar una estrategia de inactividad durante la revalidación. En esta estrategia, las páginas se pueden solicitar desde la caché y desde la red en paralelo. La respuesta proviene de la caché si está disponible, de lo contrario, de la red. La caché siempre se mantiene actualizada con la respuesta de la red con cada solicitud correcta.
3. Delega la carga previa al service worker
En la mayoría de los casos, el mejor enfoque es usar <link rel="prefetch">
. La etiqueta es una sugerencia de recursos diseñada para que la carga previa sea lo más eficiente posible.
Sin embargo, en algunos casos, podría ser mejor delegar esta tarea por completo al trabajador del servicio.
Por ejemplo, para obtener previamente los primeros productos en una página de ficha de producto renderizada del cliente, es posible que debas insertar varias etiquetas <link rel="prefetch">
de forma dinámica en la página, según una respuesta de la API. Esto puede consumir tiempo momentáneamente en el subproceso principal de la página y dificultar la implementación.
En casos como este, usa una "estrategia de comunicación de la página al trabajador de servicio" para delegar la tarea de la carga previa por completo al trabajador de servicio. Este tipo de comunicación se puede lograr con worker.postMessage():
El paquete Workbox Window simplifica este tipo de comunicación y abstrae muchos detalles de la llamada subyacente que se realiza.
La precarga con Workbox Window se puede implementar de la siguiente manera:
- En la página: Llama al service worker y pásale el tipo de mensaje y la lista de URLs para la precarga:
const wb = new Workbox('/sw.js');
wb.register();
const prefetchResponse = await wb.messageSW({type: 'PREFETCH_URLS', urls: […]});
- En el trabajador del servicio, implementa un controlador de mensajes para emitir una solicitud
fetch()
para cada URL que se precargue:
addEventListener('message', (event) => {
if (event.data.type === 'PREFETCH_URLS') {
// Fetch URLs and store them in the cache
}
});