Promesas en JavaScript ¿Qué son y para qué sirven?
En este artículo, desglosaremos cómo las Promesas transforman el caos de los procesos pendientes en un flujo de código elegante y predecible. Descubre el mecanismo que permite a tus proyectos gestionar esperas y errores sin detener la experiencia del usuario ni un solo segundo.

Índice
1. ¿Qué es una Promesa?
Una Promesa es un objeto que actúa como un marcador de posición (un placeholder) para un valor que todavía no conocemos, pero que esperamos recibir en el futuro.
Es el mecanismo oficial de JavaScript para gestionar la asincronía de forma ordenada, permitiendo que el programa sepa qué hacer cuando una tarea termine bien o cuando falle.
1.1. ¿Qué es la Asincronía? (En términos simples)
La asincronía es la capacidad de un programa para iniciar una tarea que toma tiempo y, en lugar de quedarse «congelado» esperando el resultado, seguir ejecutando otras instrucciones. Es la técnica que permite que las aplicaciones web sean fluidas y no se bloqueen cada vez que descargan algo de internet.
1.2. Ejemplo escenario: Sin promesas vs. Con promesas
Imagina que estás en una aplicación de clima en tu teléfono:
1.2.1. Escenario A: SIN PROMESAS (Bloqueante)
- Presionas el botón «Actualizar clima».
- La aplicación le pide los datos al satélite (esto tarda 5 segundos).
- El Problema: Durante esos 5 segundos, la pantalla de tu teléfono se queda totalmente congelada. No puedes volver atrás, no puedes ver el mapa, ni siquiera puedes cerrar la app. El programa está «trabado» en la línea de código que pide el clima.
- Si la conexión falla, la app simplemente se cierra o se queda en blanco para siempre porque no sabe cómo manejar el error.
1.2.2. Escenario B: CON PROMESAS (Asíncrono)
- Presionas el botón «Actualizar clima».
- La aplicación lanza la petición y recibe una Promesa al instante.
- Mientras la Promesa está en estado Pendiente (Pending), la app te muestra un iconito de carga girando, pero tú puedes seguir usando la app: puedes ver el historial, cambiar de ciudad o entrar a la configuración.
- La Solución: Cuando los datos llegan (éxito), la Promesa se resuelve y el texto del clima aparece mágicamente en pantalla. Si no hay internet (fallo), la Promesa se rechaza y la app te muestra un mensaje amigable: «Lo sentimos, revisa tu conexión».
2. ¿Para que sirven las promesas?
Estas son sus principales funcionalidades:
2.1. Para «No congelar» tu aplicación
Imagina que JavaScript es un cocinero que solo tiene una mano. Si ese cocinero se pone a hervir agua y se queda mirando la olla sin soltarla hasta que hierva, no puede cortar las verduras ni atender a los clientes. La cocina se detiene.
- SIN PROMESAS: El navegador se queda bloqueado esperando una respuesta (como una descarga). El usuario intenta hacer clic en un botón y no pasa nada.
- CON PROMESAS: El cocinero pone la olla al fuego, deja un «aviso» (la Promesa) que sonará cuando hierva, y sigue cortando verduras. Las promesas sirven para que tu página web siga siendo fluida y respondona mientras ocurren cosas pesadas de fondo.
2.2. Para gestionar la incertidumbre
Cuando pides algo por internet (como los datos de un usuario), no sabes con certeza qué va a pasar. Hay tres futuros posibles que la Promesa gestiona por ti:
- El futuro brillante:
- Los datos llegan rápido y perfectos. (Estado: Fulfilled/Resuelta).
- El futuro gris:
- No hay internet, el servidor se cayó o el usuario no existe. (Estado: Rejected/Rechazada).
- El presente:
- Todavía no sabemos qué va a pasar. (Estado: Pending/Pendiente).
Las promesas sirven para que tú, como programador, dejes instrucciones escritas para cada caso: «Si sale bien, haz A; si sale mal, haz B». Sin ellas, tu código simplemente fallaría o intentaría usar datos que no existen.
2.3. Para ordenar el caos (El «Paso a paso»)
A veces necesitas que las cosas pasen en un orden específico, pero son tareas asíncronas. Por ejemplo:
- Iniciar sesión.
- Luego, obtener el perfil del usuario.
- Luego, mostrar sus fotos.
Sin promesas, esto se convertía en un código desordenado y difícil de leer (el famoso Callback Hell). Las promesas sirven para encadenar estas tareas una detrás de otra de forma legible, como si fuera una lista de compras: «Haz esto, luego haz esto otro, luego aquello».
En resumen, las promesas sirven para:
- Esperar sin detenerse:
- Mantener la web activa mientras se cargan datos.
- Prepararse para el error:
- Tener un plan de emergencia si algo falla en la red.
- Leer el código como un libro:
- Poder seguir la lógica de arriba hacia abajo, aunque las tareas tarden diferentes tiempos en completarse.
3. ¿Cómo usar promesas?
Aquí veremos las dos situaciones más comunes usando promesas
- Usando en constructor new Promise()
- Usando funciones que retornan promesas
3.1. Sintaxis general usando new Promise()
Para crear una promesa, usamos el constructor new Promise(). Este siempre recibe una función (llamada executor) que se ejecuta inmediatamente.
const promesa = new Promise((resolve, reject) => {
// Lógica asincrónica
});Lenguaje del código: JavaScript (javascript)
3.1.1. Ejemplo completo
/**
* --- EL CONSTRUCTOR: 'new Promise' ---
* Es la forma de decirle a JS: "Voy a iniciar una tarea que terminará luego".
*/
const promesa = new Promise((resolve, reject) => {
// 👉 new Promise(...)
// Crea un objeto Promesa que manejará una operación asincrónica
// 👉 (resolve, reject) => { ... }
// Es una función ejecutora que se ejecuta automáticamente
// Tiene dos parámetros importantes:
// Simulamos una operación asincrónica (ej: API)
setTimeout(() => {
const exito = true;
if (exito) {
resolve("Operación exitosa");
// 👉 resolve(valor)
// Cambia el estado a "fulfilled"
// Envía el resultado a los .then()
} else {
reject("Ocurrió un error");
// 👉 reject(error)
// Cambia el estado a "rejected"
// Envía el error a los .catch()
}
}, 2000);
});
/**
* --- CONSUMO DE LA PROMESA ---
* Una vez que la promesa está creada, necesitamos "escuchar" cuándo termina. Para eso usamos tres métodos principales:
* .then() -> El "Camino del Éxito" - .catch() -> El "Manejador de Emergencias" - .finally() -> El "Paso Final"
*/
.then((resultado) => {
// 👉 .then()
// Se ejecuta cuando la promesa se resuelve (resolve)
// Recibe el valor pasado en resolve()
console.log(resultado);
})
.catch((error) => {
// 👉 .catch()
// Se ejecuta cuando la promesa falla (reject)
// Recibe el error pasado en reject()
console.error(error);
})
.finally(() => {
// 👉 .finally()
// Se ejecuta siempre (éxito o error)
// Ideal para limpiar estados (ej: loaders en el DOM)
console.log("Proceso finalizado");
});Lenguaje del código: JavaScript (javascript)
Componentes clave de la sintaxis:
new Promise()- Constructor que crea la promesa
- Recibe una función ejecutora
- Función ejecutora
(resolve, reject) => {}- Se ejecuta automáticamente
- Contiene la lógica asincrónica
resolve(valor)- Indica éxito
- Cambia el estado a fulfilled
- Envía datos a
.then()
reject(error)- Indica fallo
- Cambia el estado a rejected
- Envía error a
.catch()
.then()- Maneja el resultado exitoso
- Se puede encadenar
.catch()- Maneja errores
- Captura fallos de toda la cadena
.finally()- Se ejecuta siempre
- Ideal para limpiar (ej: ocultar loader en DOM)
3.2. Sintaxis usando funciones que retornan promesas
Esta es, de hecho, la forma más común y profesional de trabajar. En lugar de tener una promesa suelta, la envolvemos en una función. Esto nos permite reutilizarla y pasarle parámetros (como un ID de usuario o una URL).
Aquí tienes la sintaxis detallada:
function nombreFuncion() {
return new Promise((resolve, reject) => {
// lógica asincrónica
});
}Lenguaje del código: JavaScript (javascript)
3.2.2. Ejemplo completo
En esta parte, creamos una función normal que, al ser ejecutada, nos entrega (retorna) el objeto Promesa.
/**
* DEFINICIÓN DE LA FUNCIÓN
* @param {string} usuario - Recibe un nombre para personalizar la tarea.
* Retorna una New Promise para que quien la llame pueda usar .then() y .catch()
*/
const obtenerPermisos = (usuario) => {
// Retornamos la promesa directamente
return new Promise((resolve, reject) => {
console.log(`Verificando permisos para: ${usuario}...`);
// Simulamos una operación asíncrona de 1.5 segundos
setTimeout(() => {
const esAdministrador = true;
if (esAdministrador) {
// Si tiene éxito, mandamos un objeto con la info
resolve({ acceso: true, nivel: "VIP" });
} else {
// Si falla, mandamos el motivo del rechazo
reject("Acceso denegado: No tienes rango suficiente.");
}
}, 1500);
});
};
Lenguaje del código: JavaScript (javascript)
EJECUCIÓN: ¿Cómo se usa esta función?
Al invocar la función, esta «explota» y se convierte en una promesa. Por eso podemos encadenar los métodos de escucha inmediatamente después de los paréntesis.
/**
* LLAMADA A LA FUNCIÓN
* Al ejecutar obtenerPermisos("Alex"),
* lo que recibimos es la promesa en estado 'pending'.
*/
obtenerPermisos("Alex")
.then((resultado) => {
// 'resultado' es el objeto { acceso: true, nivel: "VIP" }
console.log(`¡Bienvenido! Tu nivel es: ${resultado.nivel}`);
})
.catch((error) => {
// Si la validación fallara, entraría aquí
console.error("Error de sistema:", error);
})
.finally(() => {
console.log("Proceso de login terminado.");
});Lenguaje del código: JavaScript (javascript)
Explicación de los Componentes en este Modo:
return new Promise(...):- Es vital. Si no pones el
return, cuando llames a la función recibirásundefinedy no podrás usar el.then().
- Es vital. Si no pones el
- Parámetros de la función (
usuario):- A diferencia de una promesa estática, aquí puedes inyectar datos dinámicos para que la promesa trabaje con ellos.
- Encadenamiento directo:
- Como la función devuelve una promesa, puedes escribir
miFuncion().then(). Esto hace que el código sea muy limpio.
- Como la función devuelve una promesa, puedes escribir
¿Por qué es mejor usar funciones?
- Reutilización: Puedes llamar a
obtenerPermisos()diez veces con diez nombres distintos. - Modularidad: Puedes tener tus promesas en un archivo aparte y exportarlas como herramientas listas para usar.
- Preparación para Async/Await: Esta estructura es obligatoria si luego quieres usar la sintaxis moderna de
async/await.
4. El método .then()
4.1. ¿Qué es exactamente .then()?
Es un método que tienen todos los objetos Promise. Su función es registrar un «callback» (una función) que se ejecutará únicamente cuando la promesa pase al estado de Fulfilled (resuelta).
4.2. Sintaxis y Componentes
Cuando consumes una promesa, .then() recibe como argumento el valor que fue enviado desde el resolve() original.
/**
* 1. SUPONEMOS UNA FUNCIÓN QUE DEVUELVE UNA PROMESA
* (Como una petición a una base de datos)
*/
const obtenerUsuario = (id) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
// Al resolver, enviamos un objeto
resolve({ id: id, nombre: "Marcos", rol: "Editor" });
}, 1000);
});
};
/**
* 2. CONSUMO CON .then()
* Llamamos a la función y "encadenamos" el método.
*/
obtenerUsuario(10)
.then((usuario) => {
// COMPONENTE: El parámetro 'usuario'
// Es el objeto que 'resolve' nos mandó desde la promesa.
console.log("¡Promesa cumplida!");
console.log(`Bienvenido, ${usuario.nombre}`); // Imprime: "Bienvenido, Marcos"
});
Lenguaje del código: JavaScript (javascript)
4.3. El Encadenamiento (La verdadera potencia)
Una de las características más importantes de .then() es que siempre devuelve una nueva promesa. Esto nos permite encadenar múltiples acciones una tras otra sin caer en el desorden.
Si dentro de un .then() retornas un valor, ese valor se pasa automáticamente al siguiente .then().
obtenerUsuario(10)
.then((usuario) => {
console.log("Paso 1: Usuario obtenido.");
// Retornamos solo el nombre para el siguiente paso
return usuario.nombre.toUpperCase();
})
.then((nombreMayus) => {
// 'nombreMayus' es el resultado del return anterior
console.log(`Paso 2: Nombre transformado: ${nombreMayus}`);
return nombreMayus.length;
})
.then((longitud) => {
// Seguimos la cadena...
console.log(`Paso 3: El nombre tiene ${longitud} letras.`);
})
.catch((error) => {
// Un solo catch al final atrapa errores de CUALQUIER .then anterior
console.error("Algo falló en la cadena:", error);
});
Lenguaje del código: JavaScript (javascript)
4.4. Puntos clave para recordar
- No es inmediato:
- Aunque la promesa se resuelva instantáneamente, el código dentro del
.then()se ejecutará en el siguiente «ciclo» de JavaScript (no bloquea el resto del script).
- Aunque la promesa se resuelva instantáneamente, el código dentro del
- Recibe el éxito:
- Si la promesa falla (
reject), el.then()se salta por completo y el flujo va directo al.catch().
- Si la promesa falla (
- Transformación:
- Puedes usar
.then()para procesar datos (limpiar un texto, filtrar una lista) antes de que lleguen a la parte final de tu programa.
- Puedes usar
5. El método .catch()
5.1. ¿Qué es .catch()?
El método .catch() es el escudo protector de tu código asíncrono. Si .then() es para cuando todo sale bien, .catch() es el plan de emergencia para cuando algo sale mal.
Es un método que se encadena a una Promesa para capturar cualquier error o rechazo que ocurra durante la operación asíncrona. Su trabajo es detener la «caída libre» de un error y permitirte manejarlo con elegancia, evitando que tu aplicación deje de funcionar o muestre mensajes extraños al usuario.
5.2. ¿Para qué sirve? (Funciones principales)
- Capturar el
reject():- Si dentro de la promesa llamaste a la función
reject("Error de red"), el bloque.catch()recibirá ese mensaje.
- Si dentro de la promesa llamaste a la función
- Capturar errores inesperados:
- Si dentro de un
.then()cometes un error de programación (como intentar leer una propiedad de algo que esundefined), el.catch()también lo atrapará.
- Si dentro de un
- Centralizar el manejo de fallos:
- No necesitas un detector de errores en cada paso; un solo
.catch()al final de una cadena de varios.then()puede vigilar a todos.
- No necesitas un detector de errores en cada paso; un solo
5.3. Sintaxis y ejemplo
Observa cómo el flujo de ejecución «salta» directamente al .catch() cuando algo falla:
/**
* 1. DEFINICIÓN: Una función que puede fallar.
* Simulamos la validación de un pago.
*/
const procesarPago = (monto) => {
return new Promise((resolve, reject) => {
console.log("Procesando pago...");
setTimeout(() => {
// Condición de error: monto insuficiente
if (monto > 0) {
resolve(`Pago de $${monto} aprobado.`);
} else {
// ACTIVACIÓN DEL ERROR
reject("Error: El monto debe ser mayor a cero.");
}
}, 2000);
});
};
/**
* 2. CONSUMO Y MANEJO DE ERRORES
*/
procesarPago(-50) // Enviamos un número negativo para forzar el error
.then((confirmacion) => {
// Este bloque SE SALTARÁ porque la promesa será rechazada
console.log(confirmacion);
})
.catch((error) => {
/**
* COMPONENTE: El parámetro 'error'
* Recibe lo que sea que mandaste en el reject().
*/
console.error("Hubo un problema con tu transacción:");
console.error(`Motivo: ${error}`); // Imprime: Motivo: Error: El monto debe ser mayor a cero.
})
.finally(() => {
console.log("Sesión de pago cerrada.");
});
Lenguaje del código: JavaScript (javascript)
5.4. Características Importantes
- El Efecto «Burbuja»:
- En una cadena de promesas, el error «flota» hacia abajo. Si tienes 5
.then()seguidos y el error ocurre en el primero, JavaScript saltará los otros 4 y caerá directo en el.catch().
- En una cadena de promesas, el error «flota» hacia abajo. Si tienes 5
- Recuperación:
- Sorprendentemente, puedes poner un
.then()después de un.catch(). Esto sirve si quieres intentar una «solución alternativa» después de un fallo.
- Sorprendentemente, puedes poner un
- Evita el «Uncaught Promise Rejection»:
- Si una promesa falla y no tienes un
.catch(), el navegador lanzará una advertencia roja en la consola que puede afectar el rendimiento o la estabilidad de tu app.
- Si una promesa falla y no tienes un
6. El método .finally()
6.1. ¿Qué es .finally()?
El método .finally() es el último eslabón en la cadena de una Promesa, se ejecuta siempre, sin importar si la Promesa fue:
- ❌ rechazada (
reject) - ✅ resuelta (
resolve)
Si el .then() es para el éxito y el .catch() es para el error, el .finally() es para lo que tiene que pasar sí o sí, sin importar el resultado.
A diferencia de los otros dos, .finally() no recibe ningún argumento. No sabe si la promesa terminó bien o mal, simplemente sabe que terminó.
6.2. Sintaxis y ejemplo.
SINTAXIS:
miPromesa()
.then(resultado => {
// Se ejecuta si todo sale bien
})
.catch(error => {
// Se ejecuta si ocurre un error
})
.finally(() => {
// ✅ Se ejecuta SIEMPRE (éxito o error)
});Lenguaje del código: JavaScript (javascript)
EJEMPLO:
Observa cómo este bloque es el «punto de encuentro» final del código:
/**
* Simulamos una petición de descarga de un archivo
*/
const descargarArchivo = () => {
return new Promise((resolve, reject) => {
console.log("Iniciando descarga...");
const hayInternet = false; // Simulamos un fallo
setTimeout(() => {
if (hayInternet) {
resolve("Archivo.pdf descargado");
} else {
reject("Error 500: Sin conexión");
}
}, 2000);
});
};
// --- CONSUMO ---
// 1. Activamos un indicador de carga en la UI (imaginario)
console.log("Estado: [CARGANDO...]");
descargarArchivo()
.then((mensaje) => {
// Solo se ejecuta si hay éxito
console.log("Éxito:", mensaje);
})
.catch((error) => {
// Solo se ejecuta si hay error
console.error("Fallo:", error);
})
.finally(() => {
/**
* COMPONENTE: .finally()
* No importa si se descargó o si falló la red,
* el estado de "Cargando" debe desaparecer siempre.
*/
console.log("Estado: [LISTO / ESPERA]");
console.log("Limpieza de memoria realizada.");
});Lenguaje del código: JavaScript (javascript)
6.3. ¿Para qué sirve? (Su función principal)
Sirve para realizar tareas de limpieza o finalización que son necesarias en ambos casos (éxito o fracaso).
Casos de uso comunes:
- Quitar un «Loading»:
- Si muestras un icono de carga (spinner) al usuario mientras pides datos, debes quitarlo tanto si los datos llegaron como si hubo un error de conexión.
- Cerrar conexiones:
- Cerrar una conexión a una base de datos o un archivo que dejaste abierto.
- Resetear formularios:
- Limpiar los campos de un formulario después de intentar enviar los datos.
