leanmind logo leanmind text logo

Blog

Refactorización Avanzada

Dominar el refactoring productivo para maximizar el retorno de la inversión.

Cómo funciona la asincronía Js & C# version

Por Ana Cáceres

Durante los últimos años he estado trabajando con TypeScript en mi día a día, generalmente haciendo uso de la asincronía para muchas cosas. Recientemente, debido a un cambio de proyecto, he empezado a trabajar en C# aplicando esto que había aprendido en JavaScript (JS) y TypeScript (TS) de forma natural, ya que a simple vista parece que lo que en JS es una Promise, en C# es una Task pero ¿realmente funcionan igual en ambos lenguajes?

Este artículo ha salido de la curiosidad de ver cómo gestionan estos lenguajes la asincronía y comprobar si, aunque al escribirlas en código se parezcan por su estructura, realmente se gestiona igual.

¿Qué es la asincronía?

La asincronía permite que el programa pueda continuar ejecutándose mientras espera que una tarea termine, como una llamada a una API, una operación de lectura de archivos o una espera por tiempo.

Es una característica fundamental en los lenguajes de programación modernos. Permite ejecutar tareas sin bloquear el flujo principal de la aplicación, lo que resulta esencial para mantener una experiencia de uso fluida y una alta eficiencia en la ejecución de procesos.

JavaScript: Event Loop, Call Stack y Microtask Queue

JavaScript es un lenguaje single-threaded, es decir, tiene un solo hilo de ejecución. Para manejar operaciones asincrónicas, utiliza una arquitectura basada en:

Call Stack

Es la pila donde se ejecuta el código sincrónico. Cada vez que se llama a una función, se añade a la pila. Cuando finaliza, se elimina.

Web APIs

Estas permiten delegar operaciones asincrónicas como setTimeout, fetch, etc., al entorno del navegador, liberando el Call Stack.

Callback Queue (Macrotask Queue)

Aquí se almacenan tareas como los setTimeout, setInterval, y eventos DOM. Cuando el Call Stack está vacío, el Event Loop mueve una tarea de esta cola al stack.

Microtask Queue

Cola especial para tareas asincrónicas de alta prioridad, que incluye:

El Event Loop trabaja con la Microtask Queue igual que con el Callback Queue, cuando el Call Stack está vacío, mueve una tarea al stack, con la diferencia de que se priorizan las microtasks.

Orden de ejecución:

  1. Ejecuta el código sincrónico
  2. Ejecuta todas las microtareas pendientes
  3. Ejecuta una tarea de la Callback Queue

Ejemplo:

    console.log("Inicio");
    setTimeout(() => console.log("setTimeout"), 0);
    Promise.resolve().then(() => console.log("Promise"));
    console.log("Fin");

Salida:

    Inicio
    Fin
    Promise
    setTimeout

Promesas y Microtasks en profundidad

Las promesas utilizan la Microtask Queue, lo que les da prioridad sobre otras tareas asincrónicas. Esto garantiza un flujo de ejecución más predecible y controlado.

Ejemplo:

    Promise.resolve().then(() => {
      console.log("Primera microtarea");
    });
    setTimeout(() => {
      console.log("Macrotarea (setTimeout)");
    }, 0);

Salida:

    Primera microtarea
    Macrotarea (setTimeout)

C#: ThreadPool y Task Parallel Library (TPL)

A diferencia de JavaScript, C# permite la ejecución multihilo de forma nativa. Para facilitar la asincronía y el paralelismo, ofrece la Task Parallel Library (TPL).

ThreadPool

Es un grupo de hilos reutilizables administrados por .NET. Cuando se crea una tarea, se toma un hilo disponible del ThreadPool sin tener que crear uno manualmente. Que .NET asigne estos hilos automáticamente no impide que se puedan gestionar manualmente si se quisiera.

Task y async/await

La TPL introduce Task y el uso de async/await para facilitar la escritura de código asincrónico y legible. Además de la gestión de las tareas y los hilos.

Ejemplo:

    using System;
    using System.Net.Http;
    using System.Threading.Tasks;
    
    class Program
    {
        static async Task Main()
        {
            Console.WriteLine("Inicio");
    
            var tarea = TrabajoLargoAsync();
    
            Console.WriteLine("Haciendo otras cosas en el hilo principal...");
    
            var resultado = await tarea;
    
            Console.WriteLine($"Resultado: {resultado}");
            Console.WriteLine("Fin");
        }
    
        static async Task<string> TrabajoLargoAsync()
        {
            Console.WriteLine("Iniciando trabajo largo...");
            await Task.Delay(2000); // Simula una operación que tarda 2 segundos
            Console.WriteLine("Trabajo terminado.");
            return "Listo";
        }
    }

Este código no bloquea el hilo principal mientras espera la respuesta HTTP.

Salida:

    Inicio
    Iniciando trabajo largo...
    Haciendo otras cosas en el hilo principal...
    Trabajo terminado.
    Resultado: Listo
    Fin

Comparación entre JavaScript y C#

Característica JavaScript C# / .NET
Modelo de ejecución Single-thread + Event Loop Multi-threaded con ThreadPool
Asincronía principal Promesas, async/await Task, async/await
Colas de ejecución Microtask y Callback Queue TaskScheduler y ThreadPool
Uso típico Web, UI Web, escritorio, servicios


Conclusión

Tanto JavaScript como C# ofrecen mecanismos potentes para trabajar con asincronía, aunque usan paradigmas diferentes. Comprender estas diferencias permite escribir código más eficiente y adaptado al entorno en el que se ejecuta.

Para tareas reactivas el modelo basado en Event Loop de JavaScript es ideal. Para tareas paralelas intensivas y de backend, la TPL y el ThreadPool de C# brindan mayor control y escalabilidad.

Recursos adicionales

Publicado el 25/06/2025 por

¿Quieres más? te invitamos a suscribirte a nuestro boletín para avisarte cada vez que recopilemos contenido de calidad que compartir.

Si disfrutas leyendo nuestro blog, ¿imaginas lo divertido que sería trabajar con nosotros? ¿te gustaría?

Impulsamos el crecimiento profesional de tu equipo de developers