Los web workers permiten ejecutar secciones de código de archivos JavaScript en paralelo en un hilo aparte; generalmente al realizar alguna aplicación web, página web, etc, todo el código JavaScript se ejecuta el un único hilo creado por el navegador; sin embargo al realizar tareas bloqueante o de alto procesamiento es aconsejable ejecutarlas fuera de este hilo para no afectar a este hilo principal.
JavaScript es un lenguaje single-thread, es decir, todo el código normalmente se ejecuta en un único hilo: el hilo principal del navegador.
El problema es que, cuando ejecutamos tareas pesadas (como cálculos complejos, procesamiento de datos o bucles intensivos), la interfaz se congela, los clics dejan de responder y la experiencia del usuario empeora.
Aquí es donde entran los Web Workers.
Los Web Workers permiten ejecutar código JavaScript en segundo plano, en un hilo separado al hilo principal. Gracias a esto podemos ejecutar tareas pesadas sin bloquear la interfaz.
Los web workers ofrece un mecanismo sencillo para ejecutar código JavaScript en segundo plano.
En esta guía aprenderás:
- ✔️ Qué son los Web Workers
- ✔️ Cómo funcionan
- ✔️ Cómo comunicarse con ellos
- ✔️ Ejemplo práctico real
- ✔️ Manejo de errores
- ✔️ Limitaciones
- ✔️ Buenas prácticas
En la anterior entrada, aprendimos a usar la API de notificaciones nativa en JavaScript.
¿Qué es un Web Worker?
Un Web Worker es un mecanismo del navegador que permite ejecutar JavaScript en un hilo independiente al hilo principal.
Esto significa que podemos:
- Realizar tareas de alto procesamiento
- Evitar bloqueos de la UI
- Mejorar el rendimiento de la aplicación
Mientras tanto, el usuario puede seguir interactuando con la página sin notar retrasos.
❓ ¿Cuándo deberías usar Web Workers?
Úsalos especialmente cuando tu aplicación necesite:
- Procesar grandes volúmenes de datos
- Ejecutar algoritmos matemáticos pesados
- Renderizar o manipular imágenes
- Procesar JSON enormes
- Operaciones intensivas de CPU
Si tu código tarda más de 50 ms en ejecutarse, podría afectar el rendimiento (INP / UX). En esos casos, un Web Worker puede ser la solución ideal.
Tipos de Web Workers
Existen principalmente dos tipos:
✔️ Dedicated Worker
Es el más común.
Solo puede ser usado por la página que lo crea.
const worker = new Worker("worker.js");✔️ Shared Worker
Puede ser compartido entre varias pestañas o ventanas.
Empezando con los web workers
Como indicamos en un comienzo los web workers se ejecuta en un proceso aislado (en paralelo); además el código que deseamos ejecutar en paralelo debe encontrarse en un archivo aparte el cual será descargado de manera asíncrona; para crear nuestro web workers debemos crear un objeto a partir de la clase Worker de la siguiente manera:
var worker = new Worker('task.js');Con tan solo crear un objeto de la clase Worker indicando el archivo a cargar basta para crear un web worker.
Los Web Workers no son lo mismo que los Service Workers.
Los Service Workers están enfocados en cache, offline y red.
Empezando con Web Workers: Pase de mensajes entre el hilo principal y el web worker
Para crear un worker basta con indicar el archivo JavaScript que se ejecutará en segundo plano:
var worker = new Worker("task.js");A partir de ese momento, task.js se ejecuta en un hilo separado.
Además de ejecutar el código JavaScript en un hilo aparte, los web workers ofrecen un mecanismo sencillo por pase de mensajes entre este hilo o proceso aparte con el hilo principal.
Este mecanismo es muy sencillo y útil de utilizar, en donde el pase de un mensaje del hilo principal desencadena un evento en el web worker.
Enviar datos al Worker
Para pasar un mensaje desde el hilo principal a un Worker se emplea el método postMessage():
valor = 50;
var myWorker = new Worker("tarea.js");
myWorker.postMessage(valor);Y como vimos en el ejemplo anterior, este pase de mensaje en realidad nos permite pasar datos del hilo principal al Worker.
Recibir datos desde el Worker
Para poder ver los mensajes que devuelve el Worker al hilo principal se emplea la propiedad onmessage:
valor = 50;
var myWorker = new Worker("tarea.js");
myWorker.postMessage(valor);
myWorker.onmessage = function (oEvent) {
console.log("Números primos : " + oEvent.data);
};Ejemplo práctico: Worker para generar números primos
Supongamos que queremos calcular todos los números primos hasta un valor dado.
Si lo hacemos en el hilo principal, el navegador podría congelarse.
El siguiente código JavaScript permite determinar todos los primos que existen desde el cero hasta un valor dado:
function checkPrimo(number) {
var divisor = 1;
var primo = 0;
for (var i = 0; i <= number; i++) {
if (number % i == 0) {
primo++;
}
if (primo > 2)
break;
}
if (primo == 2) {
return true;
}
else {
return false;
}
}
// funcion para determinar si un conjunto de numeros es primo
function checkPrimoCota(number) {
primos = "";
for (i = 0; i <= number; i++) {
if (checkPrimo(i))
primos += i + " ";
}
return primos;
}Y al pasar un mensaje al web worker desde nuestra página principal:
postMessage("¡Empezando a trabajar!");
onmessage = function (oEvent) {
postMessage("Recibido el siguiente valor: " + oEvent.data);
postMessage("Los siguientes son primos:" + checkPrimoCota(oEvent.data))
};Vea el ejemplo práctico en los enlaces de descarga al inicio y final de esta entrada.
Código en el hilo principal
let valor = 20000;
let myWorker = new Worker("tarea.js");
myWorker.postMessage(valor);
myWorker.onmessage = function(e) {
console.log(e.data);
};Errores manejados por los Workers
Al igual que ocurre con el pase de mensajes, para manejar los errores se debe de emplear una propiedad llamada onerror:
valor = 50;
var myWorker = new Worker("tarea.js");
myWorker.postMessage(valor);
myWorker.onmessage = function (oEvent) {
console.log("Números primos : " + oEvent.data);
};
myWorker.onerror = function (oEvent) {
console.log("A ocurrido un error en el archivo: " + oEvent.filename+" en la línea "+oEvent.lineno+" "+oEvent.message);
};En donde:
filename: Nombre del script que ocasionó el error.message: Error ocasionado.lineno: Línea en donde ocurrió el error.
Consideraciones acerca de los web workers
Los web workers NO pueden acceder a:
- DOM.
- Objeto window.
- Objeto document.
- Objeto parent.
Es necesario que el código JavaScript a ser ejecutado por los web workers se encuentren en archivos apartes.
Para cerrar los web workers empleamos el método close.
Para verificar el soporte de los navegadores de los web workers:
if(typeof(Worker) !== "undefined") {
// Soporta los Web worker
// Crear nuestros web workers
} else {
// No soporta los Web worker
}⚠️ Limitaciones de los Web Workers
Un Web Worker NO puede acceder a:
- ⛔ DOM
- ⛔ window
- ⛔ document
- ⛔ parent
Además:
- ✔️ El código del Worker debe estar en un archivo aparte
- ✔️ Se descargan de forma asíncrona
- ✔️ No pueden manipular directamente la UI
Cerrar un Web Worker
Desde el hilo principal:
myWorker.terminate();Desde el worker:
close();Compatibilidad de Web Workers
Antes de usarlo:
if (typeof Worker !== "undefined") {
// Soporta Web Workers
} else {
// No soporta Web Workers
}
Hoy en día, la mayoría de navegadores modernos los soportan.
Buenas prácticas
- ✔️ Úsalos para tareas realmente pesadas
- ✔️ No crees Workers dentro de bucles
- ✔️ Finaliza Workers cuando ya no se usen
- ✔️ Envía solo los datos necesarios
- ✔️ Considera usar Transferable Objects para alto rendimiento
Los Web Workers en JavaScript son una excelente herramienta para evitar bloqueos en el hilo principal y mejorar el rendimiento de tus aplicaciones web.
La siguiente API que veremos, es la de detectar eventos de luz mediante JavaScript.
Conclusiones
Los web workers pueden convertirse en una gran herramienta para evitar procesos bloqueantes en nuestro JavaScript, al lograr ejecutar código en paralelo podemos lograr un mejor desempeño de nuestras aplicaciones web.
Al ejecutar tareas en paralelo:
- ⭐ La UI sigue fluida
- ⭐ Mejoramos la experiencia del usuario
- ⭐ Aumentamos el rendimiento general
Puedes ver el ejemplo completo en los siguientes enlaces:
Acepto recibir anuncios de interes sobre este Blog.
Los web workers permiten ejecutar secciones de código de archivos JavaScript en paralelo en un hilo aparte; en esta entrada veremos cómo trabajar con los web workers.