Trabajadores Web en JavaScript

Trabajadores Web en JavaScript

Este artículo explica los Web Workers en JavaScript.

YouTube Video

javascript-web-worker.html
  1<!DOCTYPE html>
  2<html lang="en">
  3<head>
  4  <meta charset="UTF-8">
  5  <title>JavaScript &amp; HTML</title>
  6  <style>
  7    * {
  8        box-sizing: border-box;
  9    }
 10
 11    body {
 12        margin: 0;
 13        padding: 1em;
 14        padding-bottom: 10em;
 15        font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
 16        background-color: #f7f9fc;
 17        color: #333;
 18        line-height: 1.6;
 19    }
 20
 21    .container {
 22        max-width: 800px;
 23        margin: 0 auto;
 24        padding: 1em;
 25        background-color: #ffffff;
 26        border: 1px solid #ccc;
 27        border-radius: 10px;
 28        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
 29    }
 30
 31    .container-flex {
 32        display: flex;
 33        flex-wrap: wrap;
 34        gap: 2em;
 35        max-width: 1000px;
 36        margin: 0 auto;
 37        padding: 1em;
 38        background-color: #ffffff;
 39        border: 1px solid #ccc;
 40        border-radius: 10px;
 41        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
 42    }
 43
 44    .left-column, .right-column {
 45        flex: 1 1 200px;
 46        min-width: 200px;
 47    }
 48
 49    h1, h2 {
 50        font-size: 1.2rem;
 51        color: #007bff;
 52        margin-top: 0.5em;
 53        margin-bottom: 0.5em;
 54        border-left: 5px solid #007bff;
 55        padding-left: 0.6em;
 56        background-color: #e9f2ff;
 57    }
 58
 59    button {
 60        display: block;
 61        margin: 1em auto;
 62        padding: 0.75em 1.5em;
 63        font-size: 1rem;
 64        background-color: #007bff;
 65        color: white;
 66        border: none;
 67        border-radius: 6px;
 68        cursor: pointer;
 69        transition: background-color 0.3s ease;
 70    }
 71
 72    button:hover {
 73        background-color: #0056b3;
 74    }
 75
 76    #output {
 77        margin-top: 1em;
 78        background-color: #1e1e1e;
 79        color: #0f0;
 80        padding: 1em;
 81        border-radius: 8px;
 82        min-height: 200px;
 83        font-family: Consolas, monospace;
 84        font-size: 0.95rem;
 85        overflow-y: auto;
 86        white-space: pre-wrap;
 87    }
 88
 89    .highlight {
 90        outline: 3px solid #ffc107; /* yellow border */
 91        background-color: #fff8e1;  /* soft yellow background */
 92        transition: background-color 0.3s ease, outline 0.3s ease;
 93    }
 94
 95    .active {
 96        background-color: #28a745; /* green background */
 97        color: #fff;
 98        box-shadow: 0 0 10px rgba(40, 167, 69, 0.5);
 99        transition: background-color 0.3s ease, box-shadow 0.3s ease;
100    }
101  </style>
102</head>
103<body>
104    <div class="container">
105        <h1>JavaScript Console</h1>
106        <button id="executeBtn">Execute</button>
107        <div id="output"></div>
108    </div>
109
110    <script>
111        // Override console.log to display messages in the #output element
112        (function () {
113            // Override console.log
114            const originalLog = console.log;
115            console.log = function (...args) {
116                originalLog.apply(console, args);
117                const message = document.createElement('div');
118                message.textContent = args.map(String).join(' ');
119                output.appendChild(message);
120            };
121
122            // Override console.error
123            const originalError = console.error;
124            console.error = function (...args) {
125                originalError.apply(console, args);
126                const message = document.createElement('div');
127                message.textContent = args.map(String).join(' ');
128                message.style.color = 'red'; // Color error messages red
129                output.appendChild(message);
130            };
131        })();
132
133        document.getElementById('executeBtn').addEventListener('click', () => {
134            // Prevent multiple loads
135            if (document.getElementById('externalScript')) return;
136
137            const script = document.createElement('script');
138            script.src = 'javascript-web-worker.js';
139            script.id = 'externalScript';
140            //script.onload = () => console.log('javascript-web-worker.js loaded and executed.');
141            //script.onerror = () => console.log('Failed to load javascript-web-worker.js.');
142            document.body.appendChild(script);
143        });
144    </script>
145</body>
146</html>

Web Worker en JavaScript

Web Worker en JavaScript es un mecanismo que permite ejecutar código en un hilo separado del hilo principal. Esto permite realizar cálculos intensivos y operaciones de larga duración de manera asincrónica, evitando que el hilo principal se bloquee. Al usar Web Worker, mejora la capacidad de respuesta de la interfaz de usuario y se incrementa el rendimiento de la aplicación.

El uso básico de Web Worker

Veamos el uso básico de Web Worker.

Se crea un nuevo Web Worker especificando un archivo JavaScript.

1// worker.js (created as a separate file)
2onmessage = function(event) {
3    // Receive a message
4    const data = event.data;
5    // Perform heavy computation or processing
6    const result = data * 2;
7    // Return the result to the main thread
8    postMessage(result);
9};
 1// Main thread (main.js)
 2const worker = new Worker('worker.js');
 3
 4// Send a message to the worker
 5worker.postMessage(10);
 6
 7// Receive a message from the worker
 8worker.onmessage = function(event) {
 9    console.log('Result from Worker: ', event.data); // Result: 20
10};
11
12// Error handling
13worker.onerror = function(error) {
14    console.error('Worker error: ', error);
15};
  • Este código demuestra el mecanismo básico de usar un Web Worker para solicitar cálculos desde el hilo principal y recibir el resultado de forma asíncrona. Envía 10 como mensaje al Web Worker y recibe 20 como mensaje de resultado. El hilo principal y el Web Worker se comunican enviando y recibiendo mensajes para solicitar y recibir resultados de procesamiento.

Funciones básicas

Web Worker proporciona las siguientes funcionalidades básicas.

  • postMessage y onmessage Se usan para enviar y recibir mensajes entre el hilo principal y el Web Worker. Envía datos con postMessage y recíbelos con onmessage.
  • Independencia de hilos Web Worker funciona de manera completamente independiente del hilo principal. Por lo tanto, no se puede acceder a las variables y funciones definidas en el hilo principal. Los datos necesarios deben pasarse mediante postMessage.
  • Importación de scripts Para cargar scripts externos dentro de un Web Worker, utiliza importScripts().
1// mathUtils.js
2function double(n) {
3    return n * 2;
4}
1// worker.js
2importScripts('mathUtils.js');
3
4onmessage = function(event) {
5    const input = event.data;
6    const result = double(input); // mathUtils.jsの関数を使用
7    postMessage(result);
8};
 1// Main thread (main.js)
 2const worker = new Worker('worker.js');
 3
 4// Send a message to the worker
 5worker.postMessage(10);
 6
 7// Receive a message from the worker
 8worker.onmessage = function(event) {
 9    console.log('Result from Worker: ', event.data); // Result: 20
10};
11
12// Error handling
13worker.onerror = function(error) {
14    console.error('Worker error: ', error);
15};

Alternativamente, también puedes usar import como se muestra a continuación.

1// lib.js
2
3// Simulated CPU-intensive task
4export function doHeavyWork(n) {
5    return n * 2;
6}
1// worker.js
2import { doHeavyWork } from './lib.js';
3
4self.onmessage = (event) => {
5  const data = event.data;
6  const result = doHeavyWork(data);
7  self.postMessage(result);
8};
 1// Main thread (main.js)
 2const worker = new Worker('worker.js', { type: 'module' });
 3
 4// Send a message to the worker
 5worker.postMessage(10);
 6
 7// Receive a message from the worker
 8worker.onmessage = function(event) {
 9    console.log('Result from Worker: ', event.data); // Result: 20
10};
11
12// Error handling
13worker.onerror = function(error) {
14    console.error('Worker error: ', error);
15};
  • Especificando type: 'module' en el argumento de new Worker, puedes tratar el worker como un módulo ES y utilizar la sintaxis de import.

Diferencias entre Web Worker y las funciones async

Web Worker

Características
  • Aislamiento de hilos Web Worker ejecuta código JavaScript en un hilo separado. Esto permite realizar procesamientos computacionales pesados sin bloquear el hilo principal (hilo de la UI).
  • Procesamiento concurrente El uso de Web Worker permite a los programas JavaScript realizar procesamiento concurrente en varios hilos.
  • Comunicación por mensajes El Web Worker y el hilo principal no comparten datos directamente y se comunican intercambiando mensajes mediante postMessage y onmessage.
  • No puede acceder a la interfaz de usuario Web Worker no puede acceder al DOM, por lo que no puede manipular la interfaz de usuario directamente.
Casos de uso
  • Es adecuado para procesos computacionales pesados, como procesamiento de imágenes, análisis de datos y encriptación.
  • Se puede utilizar cuando no deseas bloquear el hilo principal.

async

Características
  • Simplificando el procesamiento asíncrono La función async es una sintaxis que hace el procesamiento asíncrono más legible, usando internamente Promise.
  • Un solo hilo Todas las funciones async se ejecutan en el hilo principal. Por lo tanto, necesitas idear formas para evitar bloquear el hilo de la UI.
  • Óptimo para operaciones de E/S Es adecuado para tareas asíncronas como la comunicación de red y la lectura de archivos, pero no para cálculos pesados.
Casos de uso
  • Es adecuado para la comunicación de red como las llamadas a API.
  • Es adecuado para la lectura y escritura de archivos usando APIs del navegador o Node.js.

Diferencias clave

Características Web Worker async
Entorno de Ejecución Hilo separado Hilo principal
Propósito Procesamiento en paralelo, descarga de cálculos pesados Descripción concisa de las operaciones asíncronas
Acceso al DOM No posible Posible
Método de Comunicación Paso de mensajes (por ejemplo, postMessage) No requerido (gestionado mediante llamadas directas a funciones o await)
Casos de Uso Cálculos que consumen mucho tiempo, análisis de datos Operaciones de E/S, llamadas API

Cuándo Usar Cada Uno

Para tareas intensivas en CPU, puedes usar Web Worker para reducir la carga en el hilo principal. Por otro lado, para la comunicación en red u operaciones de E/S, puedes simplificar tu código usando async/await.

Al combinar ambos de manera apropiada, puedes lograr un procesamiento asíncrono eficiente.

Ejemplos del Uso de Web Worker

Ejemplo de descarga de cálculos complejos

A continuación se muestra un ejemplo de descarga de cálculos pesados.

 1// worker.js
 2onmessage = function(event) {
 3    const num = event.data;
 4    const result = fibonacci(num);
 5    postMessage(result);
 6};
 7
 8function fibonacci(n) {
 9    if (n <= 1) return n;
10    return fibonacci(n - 1) + fibonacci(n - 2);
11}
1// Main thread
2const worker = new Worker('worker.js');
3
4worker.onmessage = function(event) {
5    console.log('Fibonacci result: ', event.data);
6};
7
8worker.postMessage(40); // Delegate heavy computation to the worker
  • Este código es un ejemplo de cómo utilizar un Web Worker para separar y ejecutar tareas pesadas como los cálculos de la secuencia de Fibonacci fuera del hilo principal.

Un ejemplo de cómo especificar el nombre de una tarea

A continuación se muestra un ejemplo de cómo enviar y recibir mensajes especificando el nombre de una tarea.

 1// worker.js
 2self.onmessage = function(event) {
 3    switch (event.data.task) {
 4        case 'add':
 5            const result = event.data.a + event.data.b;
 6            self.postMessage({ task: 'result', value: result });
 7            break;
 8        default:
 9            self.postMessage({ task: 'error', message: 'Invalid Task' });
10    }
11};
 1// Main thread
 2const worker = new Worker('worker.js');
 3
 4worker.onmessage = function(event) {
 5    switch (event.data.task) {
 6        case 'result':
 7            console.log('Task result: ', event.data.value);
 8            break;
 9        case 'error':
10            console.error('Error: ', event.data.message);
11            break;
12    }
13};
14
15worker.postMessage({ task: 'add', a: 10, b: 20 });
  • Este código es un ejemplo de cómo despachar el procesamiento en función del nombre de la tarea en el mensaje, con el Web Worker devolviendo los resultados de los cálculos o errores al hilo principal junto con el nombre de la tarea.

Notas

Cuando uses Web Worker, ten en cuenta los siguientes puntos.

  • No puede acceder al DOM Web Worker no puede manipular la interfaz de usuario ni acceder al DOM. La manipulación del DOM debe realizarse en el hilo principal.
  • Sobrecarga de comunicación Existe cierta sobrecarga al intercambiar datos entre el hilo principal y el Web Worker. Esto puede afectar el rendimiento, especialmente cuando se intercambian grandes cantidades de datos con frecuencia.
  • Política del mismo origen Los scripts de Web Worker están sujetos a la política del mismo origen. No se pueden cargar scripts desde dominios diferentes.

El uso de Web Worker puede mejorar el rendimiento y la capacidad de respuesta de tu aplicación, pero es importante usarlo adecuadamente teniendo en cuenta limitaciones como la incapacidad de manipular el DOM.

Puedes seguir el artículo anterior utilizando Visual Studio Code en nuestro canal de YouTube. Por favor, también revisa nuestro canal de YouTube.

YouTube Video