En este tema, exploraremos patrones avanzados para manejar la programación asíncrona en TypeScript. Estos patrones te permitirán escribir código más eficiente y manejable cuando trabajes con operaciones asíncronas complejas.
Contenido
Introducción a los Patrones Asíncronos Avanzados
Los patrones asíncronos avanzados son técnicas que te permiten manejar múltiples operaciones asíncronas de manera eficiente. Estos patrones son esenciales cuando trabajas con aplicaciones que requieren múltiples llamadas a APIs, procesamiento de datos en paralelo, o cualquier otra tarea que implique operaciones asíncronas complejas.
Patrón de Promesas en Cadena
El patrón de promesas en cadena se utiliza para ejecutar una serie de operaciones asíncronas en secuencia. Cada operación se ejecuta solo después de que la anterior haya completado.
Ejemplo
function fetchData(url: string): Promise<string> { return new Promise((resolve, reject) => { setTimeout(() => { resolve(`Data from ${url}`); }, 1000); }); } fetchData('https://api.example.com/data1') .then(data1 => { console.log(data1); return fetchData('https://api.example.com/data2'); }) .then(data2 => { console.log(data2); return fetchData('https://api.example.com/data3'); }) .then(data3 => { console.log(data3); }) .catch(error => { console.error('Error fetching data:', error); });
Explicación
fetchData
es una función que simula una llamada a una API y devuelve una promesa.- Las llamadas a
fetchData
se encadenan usando.then()
, asegurando que cada llamada se ejecute solo después de que la anterior haya completado. - Si alguna de las promesas falla, el error se captura en el bloque
.catch()
.
Patrón de Paralelismo
El patrón de paralelismo se utiliza para ejecutar múltiples operaciones asíncronas en paralelo y esperar a que todas completen.
Ejemplo
function fetchData(url: string): Promise<string> { return new Promise((resolve, reject) => { setTimeout(() => { resolve(`Data from ${url}`); }, 1000); }); } Promise.all([ fetchData('https://api.example.com/data1'), fetchData('https://api.example.com/data2'), fetchData('https://api.example.com/data3') ]) .then(([data1, data2, data3]) => { console.log(data1); console.log(data2); console.log(data3); }) .catch(error => { console.error('Error fetching data:', error); });
Explicación
Promise.all
toma un array de promesas y devuelve una nueva promesa que se resuelve cuando todas las promesas en el array se han resuelto.- Los resultados de las promesas se devuelven como un array en el mismo orden en que se pasaron a
Promise.all
. - Si alguna de las promesas falla, el error se captura en el bloque
.catch()
.
Patrón de Carrera
El patrón de carrera se utiliza para ejecutar múltiples operaciones asíncronas en paralelo y obtener el resultado de la primera que complete.
Ejemplo
function fetchData(url: string): Promise<string> { return new Promise((resolve, reject) => { setTimeout(() => { resolve(`Data from ${url}`); }, Math.random() * 2000); }); } Promise.race([ fetchData('https://api.example.com/data1'), fetchData('https://api.example.com/data2'), fetchData('https://api.example.com/data3') ]) .then(data => { console.log('First data received:', data); }) .catch(error => { console.error('Error fetching data:', error); });
Explicación
Promise.race
toma un array de promesas y devuelve una nueva promesa que se resuelve o rechaza tan pronto como una de las promesas en el array se resuelve o rechaza.- En este ejemplo, la primera promesa que se resuelve proporciona el resultado.
Patrón de Secuencialización
El patrón de secuencialización se utiliza para ejecutar una serie de operaciones asíncronas en secuencia, pero con un enfoque más dinámico y flexible que el encadenamiento de promesas.
Ejemplo
async function fetchData(url: string): Promise<string> { return new Promise((resolve, reject) => { setTimeout(() => { resolve(`Data from ${url}`); }, 1000); }); } async function fetchSequentially(urls: string[]): Promise<void> { for (const url of urls) { const data = await fetchData(url); console.log(data); } } const urls = [ 'https://api.example.com/data1', 'https://api.example.com/data2', 'https://api.example.com/data3' ]; fetchSequentially(urls) .then(() => { console.log('All data fetched sequentially'); }) .catch(error => { console.error('Error fetching data:', error); });
Explicación
fetchSequentially
es una función asíncrona que toma un array de URLs.- Utiliza un bucle
for...of
para iterar sobre las URLs yawait
para esperar a que cada llamada afetchData
complete antes de continuar con la siguiente. - Este enfoque es más flexible y legible que el encadenamiento de promesas.
Ejercicios Prácticos
Ejercicio 1: Promesas en Cadena
Escribe una función que realice tres llamadas a una API en secuencia y registre los resultados en la consola.
Ejercicio 2: Paralelismo
Escribe una función que realice tres llamadas a una API en paralelo y registre los resultados en la consola.
Ejercicio 3: Carrera
Escribe una función que realice tres llamadas a una API en paralelo y registre el resultado de la primera que complete.
Ejercicio 4: Secuencialización
Escribe una función que tome un array de URLs y realice llamadas a una API en secuencia, registrando cada resultado en la consola.
Soluciones
Solución Ejercicio 1
async function fetchSequentially(urls: string[]): Promise<void> { for (const url of urls) { const data = await fetchData(url); console.log(data); } } const urls1 = [ 'https://api.example.com/data1', 'https://api.example.com/data2', 'https://api.example.com/data3' ]; fetchSequentially(urls1);
Solución Ejercicio 2
Promise.all([ fetchData('https://api.example.com/data1'), fetchData('https://api.example.com/data2'), fetchData('https://api.example.com/data3') ]) .then(([data1, data2, data3]) => { console.log(data1); console.log(data2); console.log(data3); });
Solución Ejercicio 3
Promise.race([ fetchData('https://api.example.com/data1'), fetchData('https://api.example.com/data2'), fetchData('https://api.example.com/data3') ]) .then(data => { console.log('First data received:', data); });
Solución Ejercicio 4
async function fetchSequentially(urls: string[]): Promise<void> { for (const url of urls) { const data = await fetchData(url); console.log(data); } } const urls2 = [ 'https://api.example.com/data1', 'https://api.example.com/data2', 'https://api.example.com/data3' ]; fetchSequentially(urls2);
Conclusión
En esta sección, hemos explorado varios patrones avanzados para manejar la programación asíncrona en TypeScript. Estos patrones te permitirán escribir código más eficiente y manejable cuando trabajes con operaciones asíncronas complejas. Asegúrate de practicar estos patrones con los ejercicios proporcionados para reforzar tu comprensión. En el próximo módulo, nos adentraremos en herramientas y mejores prácticas para trabajar con TypeScript.
Curso de TypeScript
Módulo 1: Introducción a TypeScript
- ¿Qué es TypeScript?
- Configuración del Entorno de TypeScript
- Tipos Básicos
- Anotaciones de Tipo
- Compilando TypeScript
Módulo 2: Trabajando con Tipos
Módulo 3: Tipos Avanzados
Módulo 4: Funciones y Módulos
- Tipos de Función
- Parámetros Opcionales y Predeterminados
- Parámetros Rest
- Módulos y Espacios de Nombres
- Decoradores
Módulo 5: Programación Asíncrona
Módulo 6: Herramientas y Mejores Prácticas
- Linting y Formateo
- Pruebas de Código TypeScript
- TypeScript con Webpack
- TypeScript con React
- Mejores Prácticas