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.
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 es un lenguaje single-threaded, es decir, tiene un solo hilo de ejecución. Para manejar operaciones asincrónicas, utiliza una arquitectura basada en:
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.
Estas permiten delegar operaciones asincrónicas como setTimeout
, fetch, etc., al entorno del navegador, liberando el Call Stack.
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.
Cola especial para tareas asincrónicas de alta prioridad, que incluye:
.then()
, .catch()
, .finally()
)async
/await
queueMicrotask()
MutationObserver
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.
console.log("Inicio");
setTimeout(() => console.log("setTimeout"), 0);
Promise.resolve().then(() => console.log("Promise"));
console.log("Fin");
Salida:
Inicio
Fin
Promise
setTimeout
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.
Promise.resolve().then(() => {
console.log("Primera microtarea");
});
setTimeout(() => {
console.log("Macrotarea (setTimeout)");
}, 0);
Salida:
Primera microtarea
Macrotarea (setTimeout)
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).
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.
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.
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
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 |
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.
¿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?
Pero espera 🖐 que tenemos un conflicto interno. A nosotros las newsletter nos parecen 💩👎👹 Por eso hemos creado la LEAN LISTA, la primera lista zen, disfrutona y que suena a rock y reggaeton del sector de la programación. Todos hemos recibido newsletters por encima de nuestras posibilidades 😅 por eso este es el compromiso de la Lean Lista