Complementar las técnicas tradicionales de precarga con trabajadores de 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 puede implicar buscar un producto, elegir un artículo de la lista de resultados, agregarlo al carrito y completar la operación con la confirmación de la compra.
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 o, al menos, que no será confiable.
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 para indicar el recurso que se debe precargar.
En esta guía, exploraremos las diferentes formas en que los trabajadores en segundo plano se pueden usar como 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 siguiente página de resultados 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.
El uso del almacenamiento en caché de los trabajadores de servicio puede ayudarte a extender la vida útil de los recursos de precarga 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, después de 3 semanas de observación, Virgilio Sport observó que los tiempos de carga para la navegación a los artículos mejoraron un 78% y la cantidad de impresiones de artículos aumentó 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 trabajador de servicio que se pueden usar como complemento de <link rel="prefetch">
o incluso como reemplazo de este, delegando esta tarea por completo al trabajador de servicio.
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 en caché previo se usa para lograr un objetivo similar al de la precarga: hacer que las navegaciones sean más rápidas.
Almacenamiento en caché previo 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 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 obtener páginas de detalles de productos anticipadamente para los primeros productos de una página de fichas. 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 almacenamiento en caché previo en el trabajador de servicio:
workbox.precaching.precacheAndRoute([
'/styles/product-page.ac29.css',
// ... other entries ...
]);
2. Extiende la vida útil de los recursos de precarga
Como se mencionó anteriormente, <link rel="prefetch">
recupera y mantiene recursos en la caché HTTP durante un período limitado, después del cual se aplican las reglas de Cache-Control
para un recurso. A partir de Chrome 85, este valor es de 5 minutos.
Los trabajadores del 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 el tiempo de ejecución del trabajador del servicio para estos 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, optamos por usar una estrategia de inactividad durante la validación. En esta estrategia, las páginas se pueden solicitar de la caché y de la red de forma simultánea. 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 que se realiza correctamente.
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 de ventana de Workbox 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
}
});