Domina el manejo de operaciones asíncronas en JavaScript con Promesas y async/await. Aprende desde conceptos fundamentales hasta patrones avanzados para controlar flujos asíncronos complejos con código limpio y mantenible.
Diagrama de flujo de ejecución asíncrona con promesas
Contenido del Artículo
Fundamentos de Promesas
Las promesas representan operaciones asíncronas:
Estados
Pending, Fulfilled, Rejected
Encadenamiento
.then().catch().finally()
Asíncrono
No bloquea el hilo principal
// Crear una promesa
const miPromesa = new Promise((resolve, reject) => {
// Operación asíncrona
setTimeout(() => {
const exito = true; // Simular resultado
if (exito) {
resolve('Datos obtenidos');
} else {
reject(new Error('Fallo en la operación'));
}
}, 1000);
});
// Consumir promesa
miPromesa
.then(resultado => {
console.log(resultado);
})
.catch(error => {
console.error(error);
})
.finally(() => {
console.log('Operación finalizada');
});
Async/Await: Sintaxis Moderna
Azúcar sintáctico para trabajar con promesas:
// Función async devuelve una promesa
async function obtenerDatos() {
try {
const respuesta = await fetch('https://api.ejemplo.com/data');
if (!respuesta.ok) {
throw new Error('Error en la respuesta');
}
const datos = await respuesta.json();
return datos;
} catch (error) {
console.error('Error al obtener datos:', error);
throw error; // Relanzar para manejo superior
}
}
// Uso
(async () => {
try {
const datos = await obtenerDatos();
console.log(datos);
} catch (error) {
// Manejar error
}
})();
async/await permite escribir código asíncrono con estructura síncrona
Patrones Avanzados
Técnicas para flujos asíncronos complejos:
// Ejecución paralela
const [usuario, posts] = await Promise.all([
fetch('/usuario/1').then(r => r.json()),
fetch('/usuario/1/posts').then(r => r.json())
]);
// Timeout con Promise.race
async function fetchConTimeout(url, timeout = 5000) {
const fetchPromise = fetch(url);
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => reject(new Error('Timeout')), timeout);
});
return Promise.race([fetchPromise, timeoutPromise]);
}
// Secuencia con for...of
async function procesarElementos(elementos) {
const resultados = [];
for (const elemento of elementos) {
const resultado = await procesar(elemento);
resultados.push(resultado);
}
return resultados;
}
Patrón | Implementación | Caso de uso |
---|---|---|
Paralelo | Promise.all() | Operaciones independientes |
Carrera | Promise.race() | Timeout o primera respuesta |
Secuencial | async/await en bucle | Operaciones dependientes |
Settled | Promise.allSettled() | Necesidad de todos los resultados |
Manejo de Errores Profundo
Estrategias robustas para errores asíncronos:
// Patrón de función segura
function asyncHandler(fn) {
return async (...args) => {
try {
return await fn(...args);
} catch (error) {
// Manejo centralizado de errores
logError(error);
showUserNotification('Error en la operación');
throw error; // Opcional
}
};
}
// Uso
const obtenerDatosSeguro = asyncHandler(obtenerDatos);
// Errores en paralelo
async function fetchMultiple(urls) {
const resultados = await Promise.allSettled(
urls.map(url => fetch(url))
);
const exitosos = resultados
.filter(r => r.status === 'fulfilled')
.map(r => r.value);
const fallidos = resultados
.filter(r => r.status === 'rejected')
.map(r => r.reason);
return { exitosos, fallidos };
}