JavaScript Promise
Antes de estudiar el contenido de este capítulo, necesitas comprender qué es la programación asíncrona; puedes consultar:Programación asíncrona en JavaScript
Promise es una clase proporcionada por ECMAScript 6, cuyo propósito es escribir tareas asíncronas complejas de manera más elegante.
Promise es un objeto en JavaScript utilizado para manejar operaciones asíncronas; representa la finalización (o el fallo) final de una operación asíncrona y su valor resultante.
En pocas palabras, Promise es una "promesa" que indica que en algún momento futuro se devolverá un resultado (puede ser un resultado exitoso o un motivo de fallo).
Promise tiene tres estados:
- pending: estado inicial, ni de éxito ni de fallo
- fulfilled: significa que la operación se completó con éxito
- rejected: significa que la operación falló

Ejemplo
// Código de operación asíncrona
if (/* Operación exitosa */) {
resolve('Resultado exitoso'); // Cambia el estado de Promise a fulfilled
} else {
reject('Motivo del fallo'); // Cambia el estado de Promise a rejected
}
});
Soporte del navegador
Debido a que Promise es una adición nueva de ES6, algunos navegadores antiguos no lo admiten. Los navegadores a partir de Safari 10 de Apple y Edge 14 de Windows comenzaron a admitir las características de ES6.
A continuación se muestra el soporte de Promise en los navegadores:
| Chrome 58 | Edge 14 | Firefox 54 | Safari 10 | Opera 55 |
Cómo usar Promise
El método then()
then()El método se utiliza para especificar la función de devolución de llamada cuando el estado de Promise cambia a fulfilled o rejected.
Ejemplo
(result) => {
// Manejar el caso de éxito
console.log('Éxito:', result);
},
(error) => {
// Manejar el caso de fallo
console.error('Fallo:', error);
}
);
El método catch()
catch()El método se utiliza específicamente para manejar situaciones en las que Promise es rechazada.
Ejemplo
.then((result) => {
console.log('Éxito:', result);
})
.catch((error) => {
console.error('Fallo:', error);
});
El método finally()
finally()El método se ejecutará sin importar cuál sea el estado final de Promise.
Ejemplo
.then((result) => {
console.log('Éxito:', result);
})
.catch((error) => {
console.error('Fallo:', error);
})
.finally(() => {
console.log('Operación completada');
});
Encadenamiento de Promise
Una característica poderosa de Promise es que se pueden encadenar múltiples operaciones asíncronas.
Ejemplo
.then((result) => doSecondThing(result))
.then((newResult) => doThirdThing(newResult))
.then((finalResult) => {
console.log('Resultado final:', finalResult);
})
.catch((error) => {
console.error('Error en algún punto de la cadena:', error);
});
Métodos estáticos de Promise
Promise.all()
Espera a que todas las Promise se completen, o a que cualquier Promise falle.
Ejemplo
.then((results) => {
// results es un array que contiene todos los resultados de las Promise
console.log(results);
})
.catch((error) => {
// Si cualquier Promise falla, se entrará aquí
console.error(error);
});
Promise.race()
Devuelve el resultado de la primera Promise que se complete (ya sea éxito o fallo).
Ejemplo
.then((result) => {
// Usar el resultado de la primera Promise que se complete
console.log(result);
})
.catch((error) => {
// Si la primera Promise que se completa es fallida
console.error(error);
});
Promise.resolve() y Promise.reject()
Crea rápidamente una Promise resuelta o rechazada.
Ejemplo
const rejectedPromise = Promise.reject('Motivo de rechazo inmediato');
Ejemplos de aplicación práctica
Ejemplo 1: Usar Promise para manejar solicitudes AJAX
Ejemplo
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.onload = () => {
if (xhr.status === 200) {
resolve(xhr.response);
} else {
reject(new Error(xhr.statusText));
}
};
xhr.onerror = () => reject(new Error('Error de red'));
xhr.send();
});
}
fetchData('https://api.example.com/data')
.then((data) => {
console.log('Datos obtenidos con éxito:', data);
})
.catch((error) => {
console.error('Error al obtener los datos:', error);
});
Ejemplo 2: Usar una cadena de Promise para manejar múltiples operaciones asíncronas
Ejemplo
return fetch(`/users/${userId}`);
}
function getPosts(userId) {
return fetch(`/users/${userId}/posts`);
}
getUser(123)
.then((user) => {
console.log('Obteniendo información del usuario:', user);
return getPosts(user.id);
})
.then((posts) => {
console.log('Obteniendo publicaciones del usuario:', posts);
})
.catch((error) => {
console.error('Error en la operación:', error);
});
Preguntas frecuentes y mejores prácticas
1. Evita el anidamiento de Promise
Mala práctica (versión de Promise del infierno de callbacks):
Ejemplo
doSecondThing(firstResult).then((secondResult) => {
doThirdThing(secondResult).then((thirdResult) => {
console.log(thirdResult);
});
});
});
Buena práctica (usando encadenamiento):
Ejemplo
.then(doSecondThing)
.then(doThirdThing)
.then((finalResult) => {
console.log(finalResult);
});
2. Siempre maneja los rechazos
Olvidar manejar el rechazo de Promise provocará un error de 'rechazo de Promise no capturado'. Siempre usa.catch()otry/catch(en async/await) para manejar errores.
3. Promise no es cancelable
Una vez creada, una Promise no se puede cancelar. Si necesitas funcionalidad de cancelación, puedes considerar usar AbortController u otros patrones.
4. Respuestas a preguntas frecuentes (FAQ)
P: ¿Se puede invertir el orden de la secuencia then, catch y finally?
R: Sí, el efecto es exactamente el mismo. Pero no se recomienda hacerlo; es mejor escribir el programa en el orden then-catch-finally.
P: Aparte del bloque then, ¿se pueden usar los otros dos bloques varias veces?
R: Sí, finally se ejecutará en orden al igual que then, pero solo se ejecutará el primer bloque catch, a menos que haya una excepción dentro del bloque catch. Por lo tanto, es mejor tener solo un bloque catch y un finally.
P: ¿Cómo se interrumpe un bloque then?
R: El bloque then se ejecuta secuencialmente hacia abajo por defecto; return no puede interrumpirlo. Puedes usar throw para saltar a catch y así interrumpirlo.
P: ¿Cuándo es adecuado usar Promise en lugar de las funciones de devolución de llamada tradicionales?
R: Cuando necesitas ejecutar operaciones asíncronas secuencialmente varias veces. Por ejemplo, si quieres verificar primero el nombre de usuario y luego la contraseña mediante métodos asíncronos, es decir, necesitas verificar el nombre de usuario de forma asíncrona y luego la contraseña, Promise es muy adecuada.
P: ¿Promise es un método que convierte lo asíncrono en síncrono?
R: En absoluto. Promise es simplemente un estilo de programación mejor.
P: ¿Cuándo necesitamos escribir otro then en lugar de continuar programando en el then actual?
R: Cuando necesitas volver a llamar a una tarea asíncrona.
Promise y async/await
ES2017 introdujo async/await, que se basa en Promise y proporciona una sintaxis más intuitiva para manejar operaciones asíncronas.
Ejemplo
try {
const user = await getUser(123);
const posts = await getPosts(user.id);
console.log('Publicaciones del usuario:', posts);
} catch (error) {
console.error('Error al obtener los datos:', error);
}
}
Aunque async/await es más legible, sigue siendo importante comprender los conceptos básicos de Promise, porque es la base de async/await.
Otras extensiones