Una promesa en JavaScript es un objeto que representa el resultado eventual de una operación asíncrona. Es como una promesa en la vida real: «Prometo darte el resultado cuando la tarea esté completa». Una promesa puede estar en uno de estos tres estados:
- Pendiente: Estado inicial, ni cumplida ni rechazada.
- Cumplida: La operación se completó con éxito.
- Rechazada: La operación falló.
¿Por qué usar Promesas?
Antes de las promesas, las devoluciones de llamada (callbacks) se usaban para manejar la asincronía. Sin embargo, anidar múltiples devoluciones de llamada conducía al «infierno de las devoluciones de llamada», haciendo que el código fuera difícil de leer y mantener. Las promesas resuelven este problema al proporcionar una forma de escribir código asíncrono más claro y lineal, facilitando la gestión de tareas asíncronas y el manejo de errores.
Cómo usar Promesas en JavaScript
Crear una Promesa
Para crear una promesa, se usa new Promise
, pasando una función ejecutora con dos parámetros: resolve
y reject
. resolve
se llama cuando la promesa se cumple y reject
se llama cuando la promesa se rechaza.
const promesa = new Promise((resolve, reject) => {
setTimeout(() => {
const exito = true;
if (exito) {
resolve('¡Éxito!');
} else {
reject('¡Fallo!');
}
}, 1000);
});
En este ejemplo, después de 1 segundo, la promesa se cumplirá con el resultado «¡Éxito!» o se rechazará con «¡Fallo!».
Manejar el resultado con .then() y .catch()
Para recibir el resultado de una promesa, se utilizan los métodos .then()
y .catch()
. .then(onFulfilled)
se llama cuando la promesa se cumple y .catch(onRejected)
se llama cuando la promesa se rechaza.
promesa
.then((resultado) => {
console.log(resultado); // "¡Éxito!"
})
.catch((error) => {
console.error(error); // "¡Fallo!"
});
Encadenar Promesas
Se pueden encadenar promesas devolviendo una promesa dentro de .then()
.
primeraPromesa()
.then((resultado1) => {
return segundaPromesa(resultado1);
})
.then((resultado2) => {
console.log(resultado2);
})
.catch((error) => {
console.error(error);
});
Usar Promise.all
Promise.all
permite ejecutar múltiples promesas en paralelo y recibir los resultados cuando todas se cumplen.
const promesa1 = obtenerDatos1();
const promesa2 = obtenerDatos2();
Promise.all([promesa1, promesa2])
.then(([resultado1, resultado2]) => {
console.log(resultado1, resultado2);
})
.catch((error) => {
console.error(error);
});
Siempre maneja los errores usando .catch()
. Si se omite, los errores pueden pasar desapercibidos y causar problemas difíciles de depurar.
Cómo usar Promesas en React
En React, a menudo se necesita realizar tareas asíncronas como llamar a una API para obtener datos. Usar promesas ayuda a gestionar estas tareas de forma eficiente.
Usar la API fetch con Promesas
fetch
es una API integrada en JavaScript para obtener datos y devuelve una promesa.
fetch('https://jsonplaceholder.typicode.com/users')
.then((respuesta) => respuesta.json())
.then((datos) => {
console.log(datos);
})
.catch((error) => {
console.error('Error:', error);
});
En este ejemplo, llamamos a la API en https://jsonplaceholder.typicode.com/users
para obtener una lista de usuarios.
Usar Promesas y useEffect en un componente
import React, { useState, useEffect } from 'react';
function ListaUsuarios() {
const [usuarios, setUsuarios] = useState(null);
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/users')
.then((respuesta) => respuesta.json())
.then((datos) => {
setUsuarios(datos);
})
.catch((error) => {
console.error('Error:', error);
});
}, []);
return (
<div>
{usuarios ? (
<ul>
{usuarios.map((usuario) => (
<li key={usuario.id}>{usuario.name}</li>
))}
</ul>
) : (
<div>Cargando...</div>
)}
</div>
);
}
export default ListaUsuarios;
useEffect
con dependencias vacías[]
se ejecutará solo una vez cuando el componente se monte.- Se usa
fetch
para llamar a la API y actualizar el estadousuarios
cuando se recibe el resultado.
Comparación entre Promesas y Async/Await
Async/Await es una nueva sintaxis basada en promesas que hace que el código asíncrono se vea y se comporte un poco más como código síncrono. Utiliza try...catch
para el manejo de errores y evita el anidamiento excesivo de .then()
. Sin embargo, el uso de Async/Await requiere una comprensión sólida de las promesas. Usa Async/Await cuando desees que el código parezca síncrono, sea más legible y necesites realizar tareas asíncronas secuencialmente. Usa Promesas cuando necesites gestionar múltiples tareas asíncronas concurrentemente y necesites usar métodos como Promise.all
o Promise.race
.