Aprende qué son los Web Workers y los Service Workers, en qué se diferencian y cuándo usar cada uno para páginas más rápidas, tareas en segundo plano, caché y soporte sin conexión.

Los navegadores ejecutan la mayor parte de tu JavaScript en el hilo principal—el mismo lugar que gestiona la entrada del usuario, las animaciones y el pintado de la página. Cuando ahí ocurre trabajo pesado (parseo de grandes datos, procesamiento de imágenes, cálculos complejos), la UI puede tartamudear o “congelarse”. Los workers existen para mover ciertas tareas fuera del hilo principal o fuera del control directo de la página, de modo que tu app se mantenga responsiva.
Si tu página está ocupada realizando un cálculo de 200 ms, el navegador no puede desplazarse suavemente, responder a clics o mantener animaciones a 60 fps. Los workers ayudan permitiendo que hagas trabajo en segundo plano mientras el hilo principal se concentra en la interfaz.
Un Web Worker es un hilo JavaScript en segundo plano que creas desde una página. Es ideal para tareas intensivas en CPU que bloquearían la UI.
Un Service Worker es un tipo especial de worker que se sitúa entre tu app web y la red. Puede interceptar peticiones, cachear respuestas y habilitar funciones como soporte sin conexión y notificaciones push.
Piensa en un Web Worker como un ayudante que hace cálculos en otra habitación. Le envías un mensaje, trabaja y responde con un mensaje.
Piensa en un Service Worker como un guardián en la puerta principal. Las peticiones de páginas, scripts y llamadas a APIs pasan por él, y puede decidir si obtiene datos de la red, sirve desde caché o responde de forma personalizada.
Al final sabrás:
postMessage) en el modelo de workers y por qué la Cache Storage API es importante para funcionar sin conexiónEste resumen establece el “por qué” y el modelo mental—a continuación profundizaremos en cómo se comporta cada tipo de worker y dónde encajan en proyectos reales.
Cuando abres una página web, la mayor parte de lo que “sientes” ocurre en el hilo principal. Es responsable de dibujar píxeles (renderizado), reaccionar a toques y clics (entrada) y ejecutar gran parte del JavaScript.
Como el renderizado, el manejo de entrada y el JavaScript a menudo se turnan en el mismo hilo, una tarea lenta puede hacer esperar a todo lo demás. Por eso los problemas de rendimiento suelen manifestarse como problemas de responsividad, no solo “código lento”.
Lo que el bloqueo siente para los usuarios:
JavaScript tiene muchas APIs asíncronas—fetch(), timers, eventos—que te ayudan a evitar esperar inactivo. Pero asíncrono no hace mágicamente que el trabajo pesado ocurra al mismo tiempo que el renderizado.
Si haces cálculo costoso (procesamiento de imágenes, parseo de JSON enorme, criptografía, filtrado complejo) en el hilo principal, aún compite con las actualizaciones de UI. “Asíncrono” puede retrasar cuándo se ejecuta, pero puede seguir ejecutándose en el mismo hilo principal y causar jank cuando se ejecute.
Los workers existen para que los navegadores puedan mantener la página responsiva mientras hacen trabajo significativo.
En resumen: los workers son una forma de proteger el hilo principal para que tu app permanezca interactiva mientras hace trabajo real en segundo plano.
Un Web Worker es una manera de ejecutar JavaScript fuera del hilo principal. En lugar de competir con el trabajo de la UI (renderizado, desplazamiento, respuesta a clics), un worker corre en su propio hilo de fondo para que las tareas pesadas terminen sin hacer que la página se sienta “atascada”.
Piénsalo así: la página se mantiene enfocada en la interacción del usuario, mientras el worker maneja trabajo intensivo en CPU como parsear un archivo grande, procesar números o preparar datos para gráficos.
Un Web Worker se ejecuta en un hilo separado con su propio ámbito global. Aún tiene acceso a muchas APIs web (timers, fetch en muchos navegadores, crypto, etc.), pero está intencionalmente aislado de la página.
Hay un par de sabores comunes:
Si nunca has usado workers antes, la mayoría de ejemplos que verás son dedicated workers.
Los workers no llaman funciones directamente en tu página. En su lugar, la comunicación ocurre enviando mensajes:
postMessage().postMessage().Para datos binarios grandes, a menudo puedes mejorar el rendimiento transfiriendo la propiedad de un ArrayBuffer (para que no se copie), lo que mantiene el paso de mensajes rápido.
Debido a que un worker está aislado, hay algunas restricciones clave:
window o document. Los workers se ejecutan bajo self (un ámbito global de worker), y las APIs disponibles pueden diferir de la página principal.Usado bien, un Web Worker es una de las maneras más simples de mejorar el rendimiento del hilo principal sin cambiar lo que hace tu app—solo dónde ocurre el trabajo costoso.
Los Web Workers encajan muy bien cuando tu página se siente “atascada” porque JavaScript está haciendo demasiado trabajo en el hilo principal. El hilo principal también es responsable de las interacciones del usuario y del renderizado, así que las tareas pesadas allí pueden causar jank, clics retrasados y desplazamiento congelado.
Usa un Web Worker cuando tengas trabajo intensivo en CPU que no necesite acceso directo al DOM:
Un ejemplo práctico: si recibes un JSON grande y parsearlo hace que la UI tartamudee, mueve el parseo a un worker y luego envía el resultado de vuelta.
La comunicación con un worker se hace mediante postMessage. Para datos binarios grandes, prefiere objetos transferibles (como ArrayBuffer) para que el navegador transfiera la propiedad de la memoria al worker en lugar de copiarla.
// main thread
worker.postMessage(buffer, [buffer]); // transfiere el ArrayBuffer
Esto es especialmente útil para buffers de audio, bytes de imagen u otros bloques grandes de datos.
Los workers tienen sobrecarga: archivos adicionales, paso de mensajes y un flujo de depuración distinto. Evítalos cuando:
postMessage puede borrar el beneficio.Si una tarea puede causar una pausa notable (a menudo ~50 ms o más) y puede expresarse como “entrada → cómputo → salida” sin acceso al DOM, un Web Worker suele valer la pena. Si es mayormente actualizaciones de UI, mantenlo en el hilo principal y optimiza allí en su lugar.
Un Service Worker es un archivo JavaScript especial que se ejecuta en segundo plano del navegador y actúa como una capa de red programable para tu sitio. En lugar de ejecutarse en la página en sí, se sitúa entre tu app web y la red, permitiéndote decidir qué sucede cuando la app solicita recursos (HTML, CSS, llamadas a API, imágenes).
Un Service Worker tiene un ciclo de vida separado de cualquier pestaña:
Como puede ser parado y reiniciado en cualquier momento, trátalo como un script orientado a eventos: haz trabajo rápido, guarda estado en almacenamiento persistente y evita suponer que siempre está corriendo.
Los Service Workers están restringidos al mismo origen (mismo dominio/protocolo/puerto) y solo controlan páginas bajo su scope—usualmente la carpeta donde se sirve el archivo worker (y subcarpetas). También requieren HTTPS (excepto localhost) porque pueden afectar peticiones de red.
Un Service Worker se usa principalmente para situarse entre tu app web y la red. Puede decidir cuándo usar la red, cuándo usar datos cacheados y cuándo hacer un poco de trabajo en segundo plano—sin bloquear la página.
La tarea más común es habilitar experiencias sin conexión o en conexiones pobres cacheando recursos y respuestas.
Algunas estrategias de caché prácticas que verás:
Esto suele implementarse con la Cache Storage API y el manejo del evento fetch.
Los Service Workers pueden mejorar la percepción de velocidad en visitas siguientes mediante:
El resultado es menos peticiones de red, arranque más rápido y rendimiento más consistente en conexiones inestables.
Los Service Workers pueden habilitar capacidades en segundo plano como notificaciones push y background sync (el soporte varía por navegador y plataforma). Eso significa que puedes notificar a usuarios o reintentar una petición fallida más tarde—incluso si la página no está abierta.
Si construyes una aplicación web progresiva, los Service Workers son una pieza central detrás de:
Si solo recuerdas una cosa: Web Workers ayudan a tu página a hacer trabajo pesado sin congelar la UI, mientras que Service Workers ayudan a tu app a controlar las peticiones de red y comportarse como una app instalable (PWA).
Un Web Worker es para tareas intensivas en CPU—parseo de datos grandes, generación de miniaturas, crunching de números—para que el hilo principal se mantenga responsivo.
Un Service Worker es para manejo de peticiones y tareas del ciclo de vida de la app—soporte sin conexión, estrategias de caché, sincronización en segundo plano y notificaciones push. Se sitúa entre tu app y la red.
Un Web Worker suele estar vinculado a una página/pestaña. Cuando la página desaparece, el worker normalmente también (a menos que uses casos especiales como SharedWorker).
Un Service Worker es orientado a eventos. El navegador puede iniciarlo para manejar un evento (como una petición o push), y luego pararlo cuando esté inactivo. Eso significa que puede ejecutarse incluso cuando no hay pestañas abiertas, siempre que un evento lo despierte.
Un Web Worker no puede interceptar las peticiones de red que hace la página. Puede fetch() datos, pero no puede reescribir, cachear o servir respuestas para otras partes de tu sitio.
Un Service Worker puede interceptar peticiones de red (vía el evento fetch), decidir si va a la red, responde desde caché o devuelve un fallback.
Un Web Worker no gestiona el caché HTTP de tu app.
Un Service Worker suele usar la Cache Storage API para almacenar y servir pares request/response—esto es la base para el cacheo sin conexión y cargas “instantáneas” repetidas.
Poner un worker en marcha es mayormente cuestión de dónde se ejecuta y cómo se carga. Los Web Workers se crean directamente desde un script de página. Los Service Workers se instalan desde la página y se sitúan “delante” de las peticiones de red de tu sitio.
Un Web Worker nace cuando tu página crea uno. Apuntas a un archivo JavaScript separado y luego te comunicas mediante postMessage.
// main.js (ejecutándose en la página)
const worker = new Worker('/workers/resize-worker.js', { type: 'module' });
worker.postMessage({ action: 'start', payload: { /* ... */ } });
worker.onmessage = (event) => {
console.log('From worker:', event.data);
};
Un buen modelo mental: el archivo del worker es solo otra URL de script que la página puede obtener, pero se ejecuta fuera del hilo principal.
Los Service Workers deben registrarse desde una página que el usuario visite:
// main.js
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js');
}
Tras el registro, el navegador maneja el ciclo install/activate. Tu sw.js puede escuchar eventos como install, activate y fetch.
Los Service Workers pueden interceptar peticiones de red y cachear respuestas. Si el registro se permitiera por HTTP, un atacante en la red podría sustituir un sw.js malicioso y, de hecho, controlar visitas futuras. HTTPS (o http://localhost para desarrollo) protege el script y el tráfico que puede influir.
Los navegadores cachean y actualizan workers de forma diferente a los scripts normales de página. Planea actualizaciones:
sw.js/bundle de worker).Si quieres una estrategia de despliegue más suave, mira /blog/debugging-workers para hábitos de prueba que detecten casos límite de actualización temprano.
Los workers fallan de formas distintas al JavaScript “normal” de la página: se ejecutan en contextos separados, tienen su propia consola y pueden reiniciarse por el navegador. Una rutina sólida de depuración ahorra horas.
Abre DevTools y busca targets específicos de worker. En Chrome/Edge, a menudo verás workers listados bajo Sources (o vía la entrada “Dedicated worker”) y en el selector de contexto de la Consola.
Usa las mismas herramientas que usarías en el hilo principal:
onmessage y funciones de larga ejecución.Si los mensajes parecen “perdidos”, inspecciona ambos lados: verifica que llamas a worker.postMessage(...), que el worker tiene self.onmessage = ..., y que la forma del mensaje coincide.
Los Service Workers se depuran mejor en el panel Application:
También vigila la Consola para errores en install/activate/fetch—estos a menudo explican por qué el caché o el comportamiento sin conexión no funcionan.
Los problemas de caché son la principal pérdida de tiempo: cachear archivos equivocados (o con demasiada agresividad) puede mantener HTML/JS antiguos. Durante pruebas, intenta el comportamiento de hard reload y confirma qué se está sirviendo realmente desde la caché.
Para pruebas realistas, usa DevTools para:
Si iteras rápido en una PWA, puede ayudar generar una app base limpia (con un Service Worker y salida de build predecibles) y luego refinar estrategias de caché desde ahí. Plataformas como Koder.ai pueden ser útiles para este tipo de experimentación: puedes prototipar una app React desde un prompt de chat, exportar el código fuente y luego ajustar tu configuración de workers y reglas de caché con un ciclo de feedback más rápido.
Los workers pueden hacer que las apps sean más fluidas y capaces, pero también cambian dónde se ejecuta el código y a qué puede acceder. Un chequeo rápido sobre seguridad, privacidad y rendimiento te evitará bugs sorpresivos—y usuarios insatisfechos.
Tanto Web Workers como Service Workers están restringidos por la política de mismo origen: solo pueden interactuar directamente con recursos del mismo esquema/host/puerto (a menos que el servidor permita acceso cross-origin mediante CORS). Esto impide que un worker obtenga silenciosamente datos de otro sitio y los mezcle en tu app.
Los Service Workers tienen protecciones adicionales: generalmente requieren HTTPS (o localhost en desarrollo) porque pueden interceptar peticiones. Trátalos como código privilegiado: mantiene dependencias mínimas, evita cargar código dinámico y versiona tu lógica de caché con cuidado para que caches antiguas no sigan sirviendo archivos desactualizados.
Las funciones en segundo plano deben sentirse previsibles. Las notificaciones push son potentes, pero las solicitudes de permiso son fáciles de abusar.
Pide permiso solo cuando haya un beneficio claro (por ejemplo, después de que un usuario habilite alertas en las preferencias) y explica qué recibirán. Si sincronizas o prefetch en segundo plano, comunícalo en lenguaje claro—los usuarios notan actividad de red inesperada o notificaciones.
Los workers no son “rendimiento gratis”. Usarlos en exceso puede salirte mal:
postMessage (especialmente con objetos grandes) pueden convertirse en cuello de botella. Prefiere agrupar y usar transferables cuando corresponda.No todos los navegadores soportan cada capacidad (o los usuarios pueden bloquear permisos). Detecta características y degrada limpiamente:
if ('serviceWorker' in navigator) {
// registra service worker
} else {
// continúa sin funciones sin conexión
}
El objetivo: la funcionalidad central debe seguir funcionando, con “mejoras agradables” (sin conexión, push, cómputo pesado) añadidas cuando estén disponibles.
Los Web Workers y los Service Workers resuelven problemas distintos, por eso se complementan bien cuando una app necesita tanto computación intensa como carga fiable y rápida. Un buen modelo mental es: Web Worker = cómputo, Service Worker = red + caché, hilo principal = UI.
Imagina que tu app permite editar fotos (redimensionar, aplicar filtros, eliminación de fondo) y ver una galería más tarde sin conexión.
Este enfoque de “calcular y luego cachear” mantiene las responsabilidades claras: el worker produce salidas y el service worker decide cómo almacenarlas y servirlas.
Para apps con feeds, formularios o datos de campo:
Aun sin sincronización completa en segundo plano, un service worker mejora la percepción de velocidad sirviendo respuestas cacheadas mientras la app actualiza en segundo plano.
Evita mezclar roles:
postMessage).No. Un Service Worker se ejecuta en segundo plano, separado de cualquier pestaña, y no tiene acceso directo al DOM (los elementos HTML de la página).
Esa separación es intencional: los Service Workers están diseñados para seguir funcionando incluso cuando no hay ninguna página abierta (por ejemplo, para responder a un evento push o servir archivos cacheados). Dado que puede no existir ningún documento activo para manipular, el navegador lo mantiene aislado.
Si un Service Worker necesita afectar lo que el usuario ve, se comunica con las páginas vía mensajería (por ejemplo, postMessage) para que la página actualice la UI.
No. Web Workers y Service Workers son independientes.
Puedes usar uno solo, o combinarlos cuando necesites tanto computación como funciones de red/sin conexión.
En navegadores modernos, los Web Workers están ampliamente soportados y suelen ser la base segura.
Los Service Workers también están ampliamente soportados en versiones recientes de navegadores principales, pero tienen más requisitos y casos límite:
localhost para desarrollo).Si la compatibilidad amplia importa, trata las capacidades de Service Worker como una mejora progresiva: construye una buena experiencia base primero y añade offline/push donde esté disponible.
No automáticamente.
Las ganancias reales vienen de usar el worker adecuado para el cuello de botella adecuado y medir antes y después.
Usa un Web Worker cuando tengas trabajo intensivo en CPU que pueda expresarse como entrada → cálculo → salida y no necesite acceder al DOM.
Encaja bien para parsear/transformar grandes cargas (JSON/CSV), compresión, criptografía, procesamiento de imagen/sonido y filtrado complejo. Si el trabajo es principalmente actualizaciones de UI o lecturas/escrituras frecuentes del DOM, un worker no ayudará (y de todos modos no puede acceder al DOM).
Usa un Service Worker cuando necesites control sobre la red: soporte sin conexión, estrategias de caché, visitas repetidas más rápidas, enrutamiento de peticiones y (donde esté disponible) push/sincronización en segundo plano.
Si tu problema es “la interfaz se congela mientras calcula”, eso es un problema para Web Worker. Si tu problema es “la carga es lenta/o el modo sin conexión no funciona”, eso es asunto de Service Worker.
No. Web Workers y Service Workers son características independientes.
Puedes usar cualquiera por separado, o combinarlos cuando tu app necesite tanto computación como funciones de red/sin conexión.
Principalmente ámbito y tiempo de vida.
fetch) incluso cuando no hay ninguna página abierta, luego cerrarse cuando está inactivo.No. Los Web Workers no tienen acceso a window/document.
Si necesitas afectar la UI, envía datos de vuelta al hilo principal con postMessage() y actualiza el DOM desde el código de la página. Mantén el worker enfocado en cómputo puro.
No. Los Service Workers no tienen acceso al DOM.
Para influir en lo que ve el usuario, comunica con las páginas controladas vía mensajería (por ejemplo con la API Clients + postMessage()) y deja que la página actualice la UI.
Usa postMessage() en ambos lados.
worker.postMessage(data)self.postMessage(result)Para datos binarios grandes, prefiere transferables (como ArrayBuffer) para evitar copias:
Los Service Workers se sitúan entre tu app y la red y pueden responder a peticiones usando la Cache Storage API.
Estrategias comunes:
Elige una estrategia por tipo de recurso (app shell vs datos de API), no una regla única para todo.
Sí, pero mantén las responsabilidades claras.
Un patrón común es:
Esto evita mezclar lógica de UI en contextos de segundo plano y mantiene el rendimiento predecible.
Usa la superficie de DevTools adecuada para cada uno.
onmessage y perfila para confirmar que el hilo principal permanece responsivo.Cuando depures errores de caché, verifica siempre qué se está sirviendo realmente (red vs caché) y prueba offline/throttling.
worker.postMessage(buffer, [buffer]);