Concurrencia y subprocesamiento múltiple en JavaScript: de la A a la Z

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Concurrencia y subprocesamiento múltiple en JavaScript: de la A a la Z



JavaScript históricamente es un lenguaje de un solo hilo que opera dentro del paradigma de la programación orientada a eventos. Sin embargo, el JavaScript moderno (especialmente en el entorno Node.js) ofrece herramientas potentes para trabajar con concurrencia y subprocesamiento múltiple. En este artículo, analizaremos cómo funcionan Event Loop, Promises, async/await, Worker Threads y clustering, y cómo utilizar estos mecanismos para mejorar el rendimiento de sus aplicaciones.



1. Event Loop: la base de la concurrencia en JavaScript



Event Loop es el corazón del modelo asíncrono de JavaScript. Permite manejar múltiples operaciones sin bloquear el hilo principal de ejecución. En Node.js, Event Loop gestiona las colas de tareas (macrotasks y microtasks), garantizando una entrada/salida no bloqueante.



Ejemplo de funcionamiento de Event Loop:



console.log('Inicio');

setTimeout(() => { console.log('Temporizador 1');}, 0);

process.nextTick(() => { console.log('nextTick');});

Promise.resolve().then(() => { console.log('Promise');});

console.log('Fin');

// Salida:// Inicio// Fin// nextTick// Promise// Temporizador 1


Es importante entender el orden de ejecución: código síncrono → microtasks (process.nextTick, Promise.then) → macrotasks (setTimeout, setInterval).



2. Promises y async/await: gestión de la asincronía



Las Promises son objetos que representan el resultado de una operación asíncrona. Permiten evitar el «callback hell» y construir cadenas de llamadas. async/await es azúcar sintáctico sobre Promises, que hace que el código asíncrono se parezca al síncrono.



Ejemplo con async/await:



const fetchData = async (url) => {  const response = await fetch(url);  if (!response.ok) {    throw new Error(`Error HTTP: ${response.status}`);  }  return await response.json();};

const main = async () => { try { const data = await fetchData('https://api.example.com/data'); console.log('Datos obtenidos:', data); } catch (error) { console.error('Error:', error.message); }};

main();


Este enfoque permite ejecutar múltiples operaciones asíncronas en paralelo con Promise.all():



const [user, posts] = await Promise.all([  fetchUser(userId),  fetchPosts(userId)]);console.log(user, posts);


3. Worker Threads: verdadero subprocesamiento múltiple en Node.js



A partir de Node.js 10.5.0, el módulo worker_threads proporciona la capacidad de crear hilos (threads) reales para ejecutar tareas intensivas en CPU. Cada Worker se ejecuta en un hilo separado con su propia instancia de V8.



Ejemplo de creación de un Worker:



// main.jsconst { Worker } = require('worker_threads');

const runWorker = (workerData) => { return new Promise((resolve, reject) => { const worker = new Worker('./worker.js', { workerData });

worker.on('message', resolve); worker.on('error', reject); worker.on('exit', (code) => { if (code !== 0) { reject(new Error(`Worker detenido con código ${code}`)); } }); });};

const main = async () => { const result = await runWorker({ iterations: 1000000 }); console.log('Resultado:', result);};

main();


// worker.jsconst { parentPort, workerData } = require('worker_threads');

const heavyComputation = (iterations) => { let result = 0; for (let i = 0; i < iterations; i++) { result += Math.sqrt(i); } return result;};

const result = heavyComputation(workerData.iterations);parentPort.postMessage(result);


Worker Threads son ideales para tareas que bloquean Event Loop: procesamiento de imágenes, cálculos matemáticos, análisis de archivos grandes.



4. Clustering: escalado a múltiples procesos

\

Blogs

Book Recommendations