Concurrencia en TypeScript: hilos, gorutinas y async/await — lo analizamos en la práctica

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 en TypeScript: desde Event Loop hasta Web Workers

\n\n

¿Alguna vez has notado cómo tu navegador o aplicación Node.js se «congela» durante la ejecución de una operación matemática compleja o al procesar un JSON grande? Esa sensación familiar de impotencia cuando la interfaz deja de responder a los clics y el servidor a las nuevas solicitudes. Todo se debe a que, por defecto, JavaScript (y su estricto hermano TypeScript) es un lenguaje de un solo hilo. Pero esto no significa que estemos condenados a programas lentos. Al contrario, el uso adecuado de la concurrencia en TypeScript permite crear aplicaciones rápidas y receptivas.

\n\n

En este artículo no solo enumeraremos términos. Analizaremos cómo funcionan realmente async/await, qué se esconde bajo el capó del Event Loop, si se pueden usar «gorutinas» en TypeScript como en Go, y cuándo es conveniente aplicar hilos reales a través de Web Workers. ¡Allá vamos!

\n\n

1. Asincronía vs Paralelismo: ¿cuál es la diferencia?

\n\n

Antes de profundizar en el código, pongámonos de acuerdo en los términos. Muchos confunden estos conceptos, y es una lástima.

\n\n
    \n
  • Asincronía (concurrencia) — es la capacidad de un programa para iniciar una tarea, cambiar a otra mientras la primera espera (por ejemplo, una respuesta del servidor) y volver a ella más tarde. En un momento dado, solo se ejecuta una instrucción.
  • \n
  • Paralelismo — es la ejecución de dos o más tareas literalmente al mismo tiempo en diferentes núcleos del procesador.
  • \n
\n\n

TypeScript nos proporciona asincronía de serie. El paralelismo, en cambio, requiere la creación de hilos separados: en el navegador son los Web Workers, en Node.js — worker_threads. Recuerda esta diferencia, de lo contrario corres el riesgo de escribir código que se «ralentice» debido al bloqueo del hilo principal.

\n\n

2. Event Loop y callbacks — el fundamento de la concurrencia en TypeScript

\n\n

El secreto principal de la asincronía en JavaScript/TypeScript es el Event Loop (bucle de eventos). Imagina que tienes una cola de tareas. El hilo principal toma una tarea, la ejecuta; si es síncrona, devuelve el resultado de inmediato. Si es una operación asíncrona (por ejemplo, setTimeout o fetch), se envía «a un lado» (a Web API o libuv), mientras el hilo principal continúa ejecutando el siguiente código.

\n\n

Cuando la operación asíncrona finaliza, su callback entra en la cola (Task Queue o Microtask Queue). El Event Loop verifica constantemente si la pila de llamadas está vacía y, si lo está, toma la primera tarea de la cola y la ejecuta.

\n\n
// Ejemplo simple que lo demuestra\nconsole.log('1. Inicio');\n\nsetTimeout(() => {\n    console.log('3. Temporizador activado');\n}, 0);\n\nPromise.resolve().then(() => {\n    console.log('2. Microtarea ejecutada');\n});\n\nconsole.log('4. Fin');\n\n// Salida: 1, 4, 2, 3
\n\n

Observa: Promise (microtarea) se ejecutó antes que setTimeout (macrotarea), aunque el temporizador tenía un retardo de 0 ms. Este es un conocimiento importante para la optimización de TypeScript.

\n\n

3. Async/Await — el azúcar que lo cambia todo

\n\n

Con la llegada de ES2017, el mundo JS se dividió en un «antes» y un «después». Async/await es azúcar sintáctico sobre las promesas que hace que el código asíncrono se parezca al síncrono. No añade hilos, pero mejora radicalmente la legibilidad.

\n\n
// Función que simula un retardo\nfunction delay(ms: number): Promise<void> {\n    return new Promise(resolve => setTimeout(resolve, ms));\n}\n\n// Función asíncrona usando async/await\nasync function fetchUserData(userId: number): Promise<string> {\n    console.log(`Solicitando datos del usuario ${userId}...`);\n    await delay(2000); // Simulación de una solicitud de red\n    return `Datos del usuario ${userId}`;\n}\n\nasync function main() {\n    console.log('Inicio');\n    const user1 = await fetchUserData(1);\n    console.log(                

Blogs

Book Recommendations