Promesas y Asincronía Básica
Comprende el modelo asíncrono no bloqueante de JavaScript: el Event Loop, el ciclo de vida de una Promesa (pending, fulfilled, rejected) y el encadenamiento con .then() y .catch().
¿Por qué JavaScript es Asíncrono?
JavaScript opera sobre un único hilo de ejecución (single-threaded). Para evitar que operaciones lentas (como consultar una base de datos o solicitar datos a un servidor) congelen la interfaz de usuario, JavaScript delega estas tareas al navegador mediante su mecanismo de Event Loop (Bucle de Eventos).
Diagrama 20.1: El flujo del Event Loop: Call Stack, Web APIs, Microtask Queue (Promesas) y Callback Queue.
Los Tres Estados de una Promesa
Una Promesa es un objeto que representa la terminación o el fracaso de una operación asíncrona a futuro:
| Estado | Significado | Método de Captura |
|---|---|---|
| Pending (Pendiente) | La operación ha iniciado pero aún no ha finalizado ni fallado. | Estado inicial. |
| Fulfilled (Cumplida) | La operación concluyó con éxito y tiene un resultado disponible. | .then(resultado => ...) |
| Rejected (Rechazada) | Ocurrió un error o la operación no pudo completarse. | .catch(error => ...) |
Construcción y Consumo de una Promesa
const verificarStock = (cantidad) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (cantidad <= 10) {
resolve(`Stock confirmado para ${cantidad} unidades.`);
} else {
reject(new Error("Cantidad supera el stock disponible en bodega."));
}
}, 1500);
});
};
// Consumo con encadenamiento .then() y .catch()
verificarStock(5)
.then(mensaje => console.log("Éxito:", mensaje))
.catch(error => console.error("Fallo:", error.message))
.finally(() => console.log("Verificación finalizada."));
⚡ Simulador de Solicitud de Pedido con Promesas
Simula una petición asíncrona a un servidor remoto con resolución o rechazo controlado por una Promesa:
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Promesas en JavaScript</title>
<style>
body { font-family: Arial, Helvetica, sans-serif; padding: 25px; background: #f8fafc; }
.card-promesa { max-width: 500px; background: white; border: 1px solid #cbd5e1; border-radius: 8px; padding: 22px; }
.grupo-acciones { display: flex; gap: 8px; margin-bottom: 15px; }
button { padding: 9px 14px; border: none; border-radius: 6px; cursor: pointer; font-weight: bold; }
.btn-exito { background: #16a34a; color: white; }
.btn-fallo { background: #dc2626; color: white; }
button:disabled { opacity: 0.5; cursor: not-allowed; }
.visor-estado { padding: 15px; border-radius: 6px; font-family: monospace; background: #f1f5f9; border-left: 4px solid #64748b; font-size: 0.9rem; min-height: 48px; display: flex; align-items: center; }
.estado-pending { border-color: #f59e0b; background: #fffbeb; color: #b45309; }
.estado-fulfilled { border-color: #22c55e; background: #f0fdf4; color: #166534; }
.estado-rejected { border-color: #ef4444; background: #fef2f2; color: #991b1b; }
</style>
</head>
<body>
<div class="card-promesa">
<h3 style="margin-top: 0; color: #0f172a;">Simulador de Promesas</h3>
<p style="color: #64748b; font-size: 0.9rem;">Prueba solicitar una respuesta asíncrona (espera simulada de 1.5 segundos):</p>
<div class="grupo-acciones">
<button class="btn-exito" id="btn-ok" onclick="ejecutarPromesa(true)">Simular Respuesta Exitosa</button>
<button class="btn-fallo" id="btn-bad" onclick="ejecutarPromesa(false)">Simular Error de Servidor</button>
</div>
<div class="visor-estado" id="caja-estado">Presiona un botón para crear una Promesa (Promise).</div>
</div>
<script>
function crearPromesaSimulada(debeTriunfar) {
return new Promise((resolve, reject) => {
// Simulamos latencia de red de 1.5s
setTimeout(() => {
if (debeTriunfar) {
resolve({ codigo: 200, mensaje: "¡Matrícula confirmada en Kilopolis!" });
} else {
reject(new Error("Error 500: Tiempo de espera agotado en la base de datos."));
}
}, 1500);
});
}
function ejecutarPromesa(debeTriunfar) {
const visor = document.getElementById('caja-estado');
const btnOk = document.getElementById('btn-ok');
const btnBad = document.getElementById('btn-bad');
btnOk.disabled = true;
btnBad.disabled = true;
visor.className = "visor-estado estado-pending";
visor.textContent = "⏳ Estado: PENDING (esperando respuesta del servidor)...";
crearPromesaSimulada(debeTriunfar)
.then(datos => {
// Estado FULFILLED
visor.className = "visor-estado estado-fulfilled";
visor.textContent = `✓ Estado: FULFILLED -> ${datos.mensaje}`;
})
.catch(err => {
// Estado REJECTED
visor.className = "visor-estado estado-rejected";
visor.textContent = `✕ Estado: REJECTED -> ${err.message}`;
})
.finally(() => {
btnOk.disabled = false;
btnBad.disabled = false;
});
}
</script>
</body>
</html>
Mini-Quiz de Retención
Comprueba tu comprensión antes de pasar a la siguiente lección¿En qué orden se imprimirán los mensajes del siguiente código en la consola? console.log("A"); setTimeout(() => console.log("B"), 0); Promise.resolve().then(() => console.log("C")); console.log("D");
¿Tienes dudas con este tema?
Sócrates AI puede darte analogías y explicarte este código paso a paso.🚀 ¿Quieres dominar Manual Completo de JavaScript ES6+ y crear proyectos reales?
Aprende arquitectura limpia, desarrollo web moderno, buenas prácticas y despliegue en producción con nuestro Bootcamp Fullstack Developer con mentorías en vivo.
🏛️ Autoría y Propiedad Intelectual: Obra educativa original de David Amador para Kilopolis Academia (Solucionáticos), estructurada sobre las especificaciones y estándares abiertos del W3C, el estándar vivo de WHATWG y la documentación oficial de código abierto. © Todos los derechos reservados.