Command Palette

Search for a command to run...

Introducción a Service Workers: Proxy Entre tu App y la Red

Aprende cómo los Service Workers actúan como proxy entre tu aplicación y la red, permitiendo caching offline, push notifications y mejoras de rendimiento.

Lectura: 16 min
Nivel: Intermedio

TL;DR - Resumen rápido

  • Los Service Workers son scripts que se ejecutan en segundo plano y actúan como proxy de red
  • Permiten implementar caching offline para que tu aplicación funcione sin conexión
  • Interceptan peticiones de red usando el evento fetch
  • Tienen un ciclo de vida complejo con fases de instalación, activación y actualización
  • Son fundamentales para crear Progressive Web Apps (PWAs)

Introducción a Service Workers

Los Service Workers son una tecnología fundamental de JavaScript introducida por Google en 2014 como parte de la iniciativa Progressive Web Apps. Permiten a las aplicaciones web funcionar offline, recibir notificaciones push y mejorar el rendimiento. Se ejecutan en un hilo separado del hilo principal y actúan como un proxy de red, interceptando las peticiones que hace tu aplicación y controlando cómo se manejan.

A diferencia de los Web Workers dedicados y los Shared Workers, los Service Workers tienen un ciclo de vida complejo y persistente. Pueden continuar ejecutándose incluso cuando la página está cerrada, lo que los hace ideales para tareas en segundo plano como sincronización de datos y envío de notificaciones.

  • <strong>Caching offline</strong>: Almacenar recursos para que la app funcione sin conexión
  • <strong>Intercepción de red</strong>: Controlar cómo se manejan las peticiones HTTP
  • <strong>Push notifications</strong>: Recibir notificaciones incluso cuando la app está cerrada
  • <strong>Background sync</strong>: Sincronizar datos cuando hay conexión disponible
  • <strong>PWA foundation</strong>: Base para crear Progressive Web Apps instalables

¿Qué es un Service Worker?

Un Service Worker es un script que se ejecuta en un contexto separado de tu página web, actuando como un proxy de red. Intercepta todas las peticiones HTTP que hace tu aplicación y decide cómo manejarlas: puede servir contenido desde el cache, hacer la petición a la red, o combinar ambas estrategias.

Los Service Workers tienen un alcance (scope) que define qué URLs pueden controlar. Por defecto, un Service Worker controla todas las páginas en su directorio y subdirectorios. Esto significa que si registras un Service Worker en `/sw.js`, controlará todas las páginas en tu sitio.

  • <strong>Ejecución en segundo plano</strong>: Se ejecutan independientemente de la página
  • <strong>Alcance controlado</strong>: Solo controlan URLs dentro de su scope
  • <strong>Persistencia</strong>: Pueden ejecutarse incluso cuando la página está cerrada
  • <strong>Sin acceso al DOM</strong>: No pueden manipular elementos HTML directamente
  • <strong>HTTPS requerido</strong>: Solo funcionan en conexiones HTTPS (excepto localhost)

Requisito HTTPS

Los Service Workers solo funcionan en conexiones HTTPS por razones de seguridad. La única excepción es localhost para desarrollo. Esto previene que atacantes inyecten Service Workers maliciosos en sitios HTTP.

Registrar un Service Worker

Para usar un Service Worker, primero debes registrarlo desde tu página principal. El registro devuelve una Promise que se resuelve cuando el Service Worker se ha registrado correctamente. El método navigator.serviceWorker.register() toma la URL del archivo del Service Worker como parámetro.

Código de Registro

El registro del Service Worker se hace típicamente en el archivo principal de tu aplicación. Es buena práctica verificar que el navegador soporta Service Workers antes de intentar registrarlos.

registrar-service-worker.js
Loading code...

Este código muestra cómo registrar un Service Worker. Primero verificamos que el navegador soporte Service Workers, luego registramos el archivo del Service Worker y manejamos los eventos de éxito y error. El evento updatefound se dispara cuando se encuentra una nueva versión del Service Worker.

Archivo del Service Worker

El archivo del Service Worker contiene el código que se ejecutará en segundo plano. El Service Worker escucha eventos como install, activate y fetch para controlar su comportamiento.

service-worker-basico.js
Loading code...

Este es un Service Worker básico que escucha los eventos install, activate y fetch. Durante la instalación, abre un cache y almacena recursos. Durante la activación, limpia caches antiguos. En el evento fetch, intercepta las peticiones y las maneja según la estrategia de caching.

Mejor práctica

Siempre usa self.addEventListener() en lugar de this.addEventListener() en los Service Workers. El contexto global en un Service Worker es self, no this. También es buena práctica usar skipWaiting() durante la activación para que el nuevo Service Worker tome control inmediatamente.

Ciclo de Vida

El ciclo de vida de un Service Worker es más complejo que el de otros tipos de workers. Tiene tres fases principales: instalación, activación y actualización. Cada fase tiene eventos específicos que puedes escuchar para controlar el comportamiento del Service Worker.

Evento Install

El evento install se dispara cuando el Service Worker se instala por primera vez. Es el lugar ideal para precachear recursos críticos que tu aplicación necesita para funcionar offline. El evento install solo se dispara una vez por Service Worker.

evento-install.js
Loading code...

Este ejemplo muestra cómo usar el evento install para precachear recursos. Usamos caches.open() para abrir un cache específico y cache.addAll() para agregar múltiples recursos. El método event.waitUntil() asegura que el Service Worker no se active hasta que la instalación se complete.

Evento Activate

El evento activate se dispara cuando el Service Worker se activa y toma control de las páginas. Es el lugar ideal para limpiar caches antiguos que ya no se necesitan. El evento activate se dispara cada vez que el Service Worker se activa.

evento-activate.js
Loading code...

Este ejemplo muestra cómo usar el evento activate para limpiar caches antiguos. Usamos caches.keys() para obtener todos los caches y eliminamos aquellos que no coinciden con el cache actual. El método self.clients.claim() asegura que el Service Worker tome control de todas las páginas abiertas inmediatamente.

Actualización del Service Worker

Cuando actualizas el archivo del Service Worker, el navegador detecta el cambio y comienza el proceso de actualización. El nuevo Service Worker se instala en segundo plano mientras el antiguo sigue controlando las páginas. El nuevo Service Worker solo se activa cuando todas las páginas controladas por el antiguo se cierran.

actualizacion-service-worker.js
Loading code...

Este ejemplo muestra cómo manejar la actualización del Service Worker. El evento updatefound se dispara cuando se encuentra una nueva versión. Usamos self.skipWaiting() para que el nuevo Service Worker tome control inmediatamente, y self.clients.claim() para controlar todas las páginas abiertas.

Skip Waiting vs Wait

Por defecto, un nuevo Service Worker espera a que todas las páginas controladas por el antiguo se cierren antes de activarse. Usar self.skipWaiting() fuerza la activación inmediata, lo que es útil durante el desarrollo pero debe usarse con cuidado en producción.

Eventos Fetch

El evento fetch es donde ocurre la magia de los Service Workers. Se dispara cada vez que tu aplicación hace una petición HTTP. Puedes interceptar estas peticiones y decidir cómo manejarlas: servir desde el cache, hacer la petición a la red, o usar una estrategia híbrida.

Interceptar Peticiones

Para interceptar peticiones, escuchas el evento fetch en el Service Worker. El evento tiene una propiedad request que contiene información sobre la petición, y métodos como respondWith() para controlar la respuesta.

interceptar-peticiones.js
Loading code...

Este ejemplo muestra cómo interceptar peticiones en un Service Worker. Usamos caches.match() para verificar si la petición está en el cache. Si está, servimos la respuesta desde el cache. Si no, hacemos la petición a la red y guardamos la respuesta en el cache.

Estrategias de Caching

Hay varias estrategias de caching que puedes implementar con Service Workers. Cada estrategia tiene sus propias ventajas y desventajas, y la elección depende de tu caso de uso específico.

estrategias-caching.js
Loading code...

Este ejemplo muestra tres estrategias comunes de caching: Cache First (prioriza el cache), Network First (prioriza la red), y Stale While Revalidate (sirve del cache y actualiza en segundo plano). Cada estrategia es adecuada para diferentes tipos de recursos.

Elección de estrategia

Cache First es ideal para recursos estáticos que cambian raramente (CSS, JS, imágenes). Network First es mejor para contenido dinámico que debe estar actualizado (API responses). Stale While Revalidate es un buen compromiso que ofrece respuestas rápidas mientras mantiene el contenido actualizado.

Cache API

La Cache API es una API nativa de JavaScript que permite almacenar respuestas HTTP en el cache del navegador. Es la base para implementar caching offline con Service Workers. La Cache API es asíncrona y persistente, lo que significa que los datos permanecen incluso después de cerrar el navegador.

Abrir un Cache

Para usar la Cache API, primero debes abrir un cache usando caches.open(). Este método devuelve una Promise que se resuelve con el objeto Cache. Puedes tener múltiples caches con diferentes nombres para organizar tus recursos.

abrir-cache.js
Loading code...

Este ejemplo muestra cómo abrir un cache y agregar recursos. Usamos caches.open() para abrir el cache y cache.addAll() para agregar múltiples recursos. También mostramos cómo agregar un solo recurso con cache.put().

Leer del Cache

Para leer del cache, usas el método caches.match(). Este método busca en todos los caches una respuesta que coincida con la petición. Devuelve una Promise que se resuelve con la respuesta si se encuentra, o undefined si no se encuentra.

leer-cache.js
Loading code...

Este ejemplo muestra cómo leer del cache. Usamos caches.match() para buscar una respuesta en el cache. Si encontramos una respuesta, la servimos. Si no, hacemos la petición a la red y la agregamos al cache.

Eliminar del Cache

Para eliminar recursos del cache, usas el método cache.delete(). Este método elimina una respuesta específica del cache. También puedes eliminar un cache completo usando caches.delete().

eliminar-cache.js
Loading code...

Este ejemplo muestra cómo eliminar recursos del cache. Usamos cache.delete() para eliminar una respuesta específica, y caches.delete() para eliminar un cache completo. También mostramos cómo eliminar caches antiguos usando caches.keys().

Limpieza de cache

Los caches pueden crecer indefinidamente si no los limpias periódicamente. Es buena práctica implementar una estrategia de limpieza que elimine caches antiguos o recursos que ya no se necesitan. Esto evita que el cache consuma demasiado espacio de almacenamiento.

Resumen: Service Workers

Conceptos principales:

  • Los Service Workers actúan como proxy de red entre tu app y el servidor
  • Interceptan peticiones HTTP usando el evento fetch
  • Tienen un ciclo de vida con fases de instalación, activación y actualización
  • Usan la Cache API para almacenar respuestas HTTP offline
  • Solo funcionan en conexiones HTTPS (excepto localhost)

Mejores prácticas:

  • Usa self.addEventListener() en lugar de this.addEventListener()
  • Precachea recursos críticos en el evento install
  • Limpia caches antiguos en el evento activate
  • Elige la estrategia de caching adecuada para cada tipo de recurso
  • Implementa limpieza periódica del cache para evitar consumo excesivo