Crear, encadenar y manejar promesas con combinadores modernos.
Fundamentos de Promesas
- Estados: pending (pendiente), fulfilled (resuelta), rejected (rechazada).
- Encadenamiento:
thenrecibe el valor resuelto y devuelve otro valor o promesa. Si devuelve un valor, la promesa siguiente se resuelve con ese valor. - Errores:
catchcaptura errores en cualquier punto de la cadena. Un error lanzado dentro dethensalta al primercatch. - Limpieza:
finallyse ejecuta siempre, ideal para ocultar loaders. - Promesa "envolvente": Si devuelves una promesa dentro de
then, la cadena espera a que esa promesa termine.
javascript1const promesa = new Promise((resolve, reject) => { 2 setTimeout(() => resolve("OK"), 1000); 3}); 4 5promesa 6 .then((res) => res + "!") 7 .then((res) => console.log(res)) 8 .catch((err) => console.error(err)) 9 .finally(() => console.log("Fin"));
Encadenamiento
- Pasar datos entre
.then()para crear flujos secuenciales. - Mejor legibilidad que los callbacks anidados.
- Regla clave: cada
thendebe devolver algo (valor o promesa) para mantener el flujo.
javascript1const getUser = () => Promise.resolve({ id: 1 }); 2const getPosts = (id) => Promise.resolve(["a", "b"]); 3 4getUser() 5 .then((u) => getPosts(u.id)) 6 .then((posts) => console.log("Posts:", posts)) 7 .catch((err) => console.error("Fallo:", err));
Combinadores
- Promise.all: Espera todas; si una falla, falla todo. Útil cuando necesitas todos los datos.
- Promise.allSettled: Espera todas sin importar fallos. Útil para mostrar resultados parciales.
- Promise.race: Devuelve la primera en completarse (éxito o error). Útil para timeouts.
- Promise.any: Devuelve la primera que se resuelve correctamente; si todas fallan, lanza error.
javascript1const a = fetch("/api/a"); 2const b = fetch("/api/b"); 3 4Promise.all([a, b]).then(async ([ra, rb]) => { 5 const dataA = await ra.json(); 6 const dataB = await rb.json(); 7 console.log(dataA, dataB); 8}); 9 10const timeout = new Promise((_, reject) => 11 setTimeout(() => reject("Timeout"), 2000) 12); 13Promise.race([fetch("/api"), timeout]);
javascript1// allSettled para mostrar resultados parciales 2Promise.allSettled([fetch("/a"), fetch("/b")]).then((results) => { 3 results.forEach((r) => console.log(r.status)); 4});
javascript1// any: primera promesa resuelta correctamente 2Promise.any([ 3 Promise.reject("Error A"), 4 Promise.resolve("OK B"), 5]).then((v) => console.log(v));
Ejemplos de Código
3 ejemplos
Crear promesa
1const p = new Promise((resolve) => setTimeout(resolve, 500));Promesas en paralelo
1Promise.all([p1, p2]).then(([a, b]) => console.log(a, b));Timeout con race
1const timeout = new Promise((_, reject) => setTimeout(() => reject("Timeout"), 2000));
2Promise.race([fetch("/api"), timeout]);Recursos
4 recursos disponibles
¡Hora de Practicar!
Práctica guiada - Refactor a promesas
Práctica
Reescribir ejercicios de callbacks usando promesas.
Desafío de Código
Ejercicios - Combinadores
Ejercicios
(1) Cargar recursos con Promise.all, (2) aplicar timeout con race, (3) manejar errores con allSettled.
Documentación Oficial
JavaScript.info - Promises
Introducción clara a promesas y patrones comunes.
Reto de Lectura
Auditoría IA #2 — El código asíncrono generado
Genera con tu IA una función que consuma una API con manejo de errores, y audítala. El código async de la IA casi siempre esconde los mismos 4 pecados — aprende a verlos.
El código asíncrono es donde la IA más te puede meter un bug silencioso: el código que "maneja errores" tragándoselos. Hoy auditas eso.
Paso 1 — Genera (10 min). Pídele a tu IA:
"Hazme una función en JavaScript que cargue la lista de usuarios de https://jsonplaceholder.typicode.com/users y para cada usuario cargue sus posts (https://jsonplaceholder.typicode.com/posts?userId=N), con manejo de errores"
Paso 2 — Audita (40 min) con esta checklist:
| # | Revisa | Pregunta clave |
|---|---|---|
| 1 | Errores tragados | ¿El catch solo hace console.log? Entonces quien llama a la función recibe undefined y NO SABE que falló. ¿Qué debería hacer: relanzar, devolver un estado de error explícito? |
| 2 | response.ok | fetch no rechaza en un 404/500 — solo en fallos de red. ¿El código revisa response.ok antes del .json()? |
| 3 | Secuencial vs paralelo | ¿Carga los posts de cada usuario UNO POR UNO con await en un loop? Con 10 usuarios son 10 viajes en fila. ¿Dónde entraría Promise.all? |
| 4 | forEach(async ...) | Si usó forEach con callback async: ese loop NO espera a nadie. ¿La función puede "terminar" antes de que lleguen los datos? |
| 5 | Verificación real | Córrelo en la consola del navegador. Luego cambia la URL a una inexistente y córrelo de nuevo: ¿te enteras del error o falla en silencio? |
Paso 3 — Informe (entregable): (a) prompt exacto, (b) mínimo 3 hallazgos con la línea citada y el escenario donde muerde, (c) tu versión corregida COMPLETA y funcionando, (d) veredicto: ¿qué pasaría si esto llegara a producción tal cual?
Clase 14 de 33 en la ruta Desarrollo web