Existe una forma de evitar que el navegador viaje hasta Internet cada vez que necesita un archivo CSS, una imagen o un script de JavaScript. La respuesta está en los service workers, una tecnología que actúa como una capa intermedia entre el navegador y el servidor, permitiéndonos interceptar cada petición y devolver recursos almacenados de forma local. El resultado es una carga notablemente más rápida y un control total sobre la estrategia de caché.
¿Qué es un service worker y por qué mejora el rendimiento?
Un service worker es un script que el navegador ejecuta en un hilo separado, en su propio contexto, independiente de la página. Al instalarlo, ganamos la capacidad de escuchar todos los fetch que realiza el navegador, es decir, cada request hacia Internet. Esto nos permite decidir si entregamos el recurso directamente desde el caché local o si lo solicitamos al servidor [0:26].
La estrategia se divide en tres pasos fundamentales:
- Instalar el service worker en el navegador.
- Escuchar cada fetch mediante un listener que intercepta las peticiones.
- Mantener un caché donde se guardan y recuperan los recursos según reglas definidas.
Cuando el navegador solicita un recurso, el service worker verifica primero si ya existe en el caché. Si lo encuentra, lo devuelve de inmediato sin conectarse a Internet. Si no lo encuentra, realiza el fetch hacia el servidor, evalúa la respuesta y, de cumplir ciertas condiciones, la almacena para futuras peticiones [1:32].
¿Cómo funciona la lógica de caché o fetch?
El archivo service-worker.js se ubica en la raíz del proyecto y contiene toda la lógica. Dentro de él se registra un listener en el evento fetch que ejecuta una función llamada o caché o fetch: dame la respuesta del caché o tráemela desde Internet [2:20].
¿Cómo se verifica el caché?
Se utiliza la Web API caches, una función asíncrona que permite hacer un match contra el request entrante. Si encuentra coincidencia, la variable response contiene el recurso y se retorna al navegador sin salir a Internet [2:42].
¿Qué validaciones se aplican antes de guardar en caché?
Cuando el recurso no está en caché, el service worker hace un fetch real y antes de almacenar la respuesta valida tres condiciones [3:16]:
- Que la respuesta sea válida.
- Que el HTTP status sea 200, lo cual indica que todo salió bien.
- Que sea una respuesta de tipo básica, es decir, del mismo dominio de la página.
Además, una función llamada isAssetCSS compara la URL contra una expresión regular que detecta extensiones como .png, .gif, .jpg, .css y otras. Solo los assets propios del sitio se almacenan [3:44].
¿Por qué se clona la respuesta?
La respuesta del fetch debe clonarse antes de guardarla. Esto se debe a que el objeto response es un stream que solo puede consumirse una vez: una copia va al caché y la otra se entrega al navegador. Se usa la Web API caches.open con un nombre de caché previamente definido y se almacena con un par clave-valor donde la clave es event.request y el valor es la respuesta clonada [4:14].
¿Cómo se ve el service worker en acción?
Al compilar el proyecto con npm start y acceder a localhost:5000, la pestaña Application de Google Chrome muestra el service worker activo para la página [5:20]. En la pestaña Network aparece un ícono especial indicando que ciertos requests fueron resueltos por el service worker en lugar de ir al servidor.
Los archivos CSS e imágenes PNG ya provienen del caché local. Si se expande la sección de cache storage en Application, se pueden ver los assets almacenados e incluso eliminarlos manualmente. Al recargar, el service worker vuelve a poblar el caché automáticamente [6:12].
Más allá del caché, los service workers habilitan estrategias avanzadas como prefetching de recursos que los usuarios necesitarán, experiencias offline propias de las progressive web applications y la delegación de tareas pesadas en segundo plano [6:55].
Si ya implementaste un service worker o tienes ideas para optimizar esta estrategia, comparte tu experiencia y las mejoras que encontraste.