El primer lenguaje en el que aprend铆 a trabajar de forma as铆ncrona fue JavaScript. Al principio, me cost贸 mucho trabajo porque era una forma de pensar completamente distinta a la que aprend铆 en la universidad. Una vez que logr茅 interiorizar los principios de la programaci贸n as铆ncrona, me fue mucho m谩s sencillo. Entonces, cuando comenc茅 a trabajar en C#, de inmediato detect茅 las similitudes entre las Task
y las Promise
, pues son pr谩cticamente equivalentes.
Pero al intentar encadenar promesas de la misma forma en la que se hace en JavaScript, me top茅 con una peculiaridad. La funci贸n que se recibe en el m茅todo .then
de JavaScript es una funci贸n que espera el valor que est谩 envuelto en la promesa. Es decir, si tenemos una Promise<number>
, la funci贸n del .then
es una funci贸n que recibe un number
. En cambio, en C# el “equivalente” a .then
es .ContinueWith
, pero este m茅todo espera una funci贸n que recibe una Task
del mismo tipo que la Task
original. Es decir, si tenemos un Task<string>
, el m茅todo .ContinueWith
recibe una funci贸n que recibe un Task<string>
. Esto me caus贸 mucha confusi贸n, y conversando con ChatGPT logr茅 tener m谩s claridad en el caso.
En caso de querer revisar mi proceso, esta es la conversaci贸n
.then
en Javascript
En JavaScript, el m茅todo .then
se utiliza para manejar el resultado de una promesa. El manejador de .then
recibe directamente el valor resuelto de la promesa. Adem谩s, JavaScript proporciona el m茅todo .catch
para manejar errores.
Ejemplo en JavaScript:
fetch('http://example.com')
.then(response => response.json())
.then(data => {
console.log(data);
})
.catch(error => {
console.error('Error:', error);
});
En este ejemplo, si la promesa se resuelve, el manejador en el primer .then
recibe el response y lo procesa. Si ocurre un error, el manejador en .catch
se ejecuta.
.ContinueWith
en C#
En C#, el m茅todo .ContinueWith
de una Task
se utiliza para continuar con la ejecuci贸n de c贸digo despu茅s de que una tarea se complete. A diferencia de .then
, el manejador de .ContinueWith
recibe una instancia de Task<T>
, lo que permite acceder a m谩s detalles acerca de la tarea, incluyendo su estado, excepciones y resultado.
Ejemplo b谩sico en C#:
Task<int> task = Task.Run(() => {
// Simulando una operaci贸n as铆ncrona
return 42;
});
task.ContinueWith(t => {
if (t.IsFaulted)
{
// Manejar excepciones
Console.WriteLine($"Error: {t.Exception.InnerException.Message}");
}
else if (t.IsCompletedSuccessfully)
{
// Manejar el resultado exitoso
Console.WriteLine($"Resultado: {t.Result}");
}
});
En este ejemplo, ContinueWith maneja tanto el resultado exitoso como las posibles excepciones. Esto es posible porque ContinueWith proporciona acceso a la tarea completa.
El porqu茅
No hay .catch
en C#
En C#, no existe un m茅todo equivalente a .catch
de las promesas en JavaScript que se encadene directamente a una Task
. En cambio, los errores se manejan dentro del mismo manejador ContinueWith
o utilizando bloques try-catch en combinaci贸n con await
.
Opciones de .ContinueWith
en C#
El m茅todo .ContinueWith
tambi茅n permite especificar opciones que controlan cu谩ndo se debe ejecutar el manejador de continuaci贸n, tales como OnlyOnRanToCompletion
y OnlyOnFaulted
.
Ejemplo con opciones de ContinueWith:
Task<int> task = Task.Run(() => {
// Simulando una operaci贸n que puede lanzar una excepci贸n
throw new InvalidOperationException("Error simulado");
return 42;
});
task.ContinueWith(t => {
Console.WriteLine($"Resultado: {t.Result}");
}, TaskContinuationOptions.OnlyOnRanToCompletion);
task.ContinueWith(t => {
Console.WriteLine($"Error: {t.Exception.InnerException.Message}");
}, TaskContinuationOptions.OnlyOnFaulted);
En este ejemplo, se definen dos manejadores de continuaci贸n: uno que se ejecuta solo si la tarea se completa con 茅xito (OnlyOnRanToCompletion
) y otro que se ejecuta solo si la tarea falla (OnlyOnFaulted
).
Conclusiones
Aunque tanto .ContinueWith
en C# como .then
en JavaScript sirven para continuar con la ejecuci贸n de c贸digo despu茅s de una operaci贸n as铆ncrona, hay diferencias importantes:
- Manejador de Continuaci贸n: En JavaScript, el manejador
.then
recibe el valor resuelto de la promesa. En C#, el manejador.ContinueWith
recibe una instancia deTask<T>
, proporcionando acceso a m谩s detalles de la tarea. - Manejo de Errores: JavaScript utiliza
.catch
para manejar errores. En C#, se manejan dentro del manejadorContinueWith
o mediante bloques try-catch cuando se usaawait
. - Opciones de Continuaci贸n: C# permite especificar opciones en
.ContinueWith
para controlar cu谩ndo se debe ejecutar el manejador de continuaci贸n, ofreciendo un control m谩s granular.
Estas diferencias reflejan las distintas filosof铆as y capacidades de los lenguajes, proporcionando a los desarrolladores herramientas poderosas para manejar operaciones as铆ncronas en cada entorno.
Espero que este art铆culo te sea 煤til para entender mejor las diferencias entre .ContinueWith en C# y .then en JavaScript, as铆 como las opciones para manejar errores y acceder a los detalles de las tareas en C#.