Promesas JS - SoniaHarry/Course-Checkpoint-8 GitHub Wiki
Una promesa es un objeto que representa un valor que puede estar disponible ahora, en el futuro o nunca. Esta representación encapsula el resultado (éxito o error) de una operación asíncrona.
Las promesas en Javascript se representan a través de la clase Promise.
Vamos a indagar un poco más en la definición de una promesa. Una promesa como su nombre indica es algo que, en principio pensamos que se cumplirá, pero en el futuro pueden ocurrir varias cosas y aquí es donde tenemos que hablar de los diferentes estados de las promesas:
- La promesa se cumple (promesa resuelta) -> aceptada
- La promesa no se cumple (promesa rechazada) -> rechazada
- La promesa se queda en un estado incierto indefinidamente (promesa pendiente) -> pendiente
Además debemos tener claro que existen dos partes importantes de las promesas:
- Cómo consumirlas (utilizar promesas)
- Cómo crearlas (preparar una función para que use promesas y se puedan consumir).
Cada promesa tiene los siguientes métodos:
- then(resolve) -> Ejecuta la función callback resolve cuando la promesa se cumple.
- catch(reject) -> Ejecuta la función callback reject cuando la promesa se rechaza.
- then(resolve,reject) -> Método equivalente a las dos anteriores en el mismo .then().
- finally(end) -> Ejecuta la función callback end tanto si se cumple como si se rechaza.
NOTA: Se tiende a no anidar promesas, evitando así el famoso Callback Hell, y haciendo el código mucho más legible. Un Callback Hell es un concepto en JavaScript que significa que nuestra asincronía se vuelve loca y no podemos gestionarla.
Si la promesa se cumple, el callback de cumplimiento se ejecutará, de lo contrario se ejecuta el callback de error.
Para gestionar todo esto con las promesas de JavaScript usamos funciones callback "gestores de promesas". Estas funciones callbacks están definidas en el método anidado then(). Y son dos:
-
resolve(value) -> Esta función indica que la tarea asincrónica se realizó correctamente. Esto ejecutará el callback de cumplimiento en el controlador then().
-
reject(error) -> Esta función indica un error mientras se intenta realizar la tarea asincrónica. Esta ejecutará el callback de error en el controlador then().
Ejemplo:
La otra cosa que debemos hacer es construir lo que se llama .catch para rechazar. Por lo tanto; .then se asigna para resolver y .catch se asigna para rechazar.
const miPromesa = new Promise((resolve, reject) => {
let a=false;
setTimeout(() => {
return (a) ? resolve('se encontró a'): reject('lo siento, no se encontró a');
}, 300);
});
miPromesa
.then(data => {console.log(data);})
.catch(err => {console.error(err);});
Nos devuelve:
En este caso se rechaza porque hemos puesto que la variable a=false y como no se cumple la condición entra por el reject.
Las promesas se definen en JavaScript llamando a la clase Promise y construyendo un objeto como en el siguiente ejemplo:
Ejemplo 1:
const miPromesa = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('valor que eventualmente devolverá la promesa');
}, 300);
});
console.log(miPromesa);
Nos devuelve el objeto:
Aunque, crear un objeto no es la única forma de definir una promesa. También puedes usar la API incorporada Promise para lograr lo mismo.
Ejemplo 2:
const miPromesa = Promise.resolve("este es el valor que eventualmente devolverá la promesa")
console.log(miPromesa);
NOTA: Mientras que la promesa en el primer ejemplo esperará 3 segundos antes de cumplir la promesa con el mensaje este es el mensaje que eventual..., la promesa en el segundo ejemplo cumplirá inmediatamente y con el mismo mensaje.
Una promesa también puede ser rechazada. La mayoría del tiempo, se rechazan porque JavaScript encuentra algún tipo de error mientras ejecuta el código asincrónico. En ese escenario, llama la función reject().
Ejemplo:
const miPromesa = new Promise((resolve, reject) => {
let a = false;
setTimeout(() => {
return (a) ? resolve('se encontró a'): reject('lo siento, no se encontró a');
}, 300);
});
miPromesa
.then(data => {console.log(data);})
.catch(err => {console.error(err);});
Nos devuelve:
En este caso después de un tiempo de espera de 3 segundos, la promesa se resolverá con un rechazo porque la declaración (a)? se resuelve en falso, lo que desencadenará reject.
Cuando finalmente la promesa devuelva un valor, normalmente querrás hacer algo con ese valor devuelto. Para ello se pueden definir las dos funciones callback que quieres llamar cuando una promesa se cumple o se rechaza. Estas funciones se definen dentro de un método then() anidado:
Ejemplo:
const miPromesa = new Promise((resolve, reject) => {
setTimeout(() => {
resolve ('Este es el valor eventual que devolverá la promesa');
}, 300);
});
miPromesa
.then(data => {console.log(data);})
Nos devuelve:
Se pueden anidar tantas promesas como se quiera. Cada paso se ejecutará después del paso anterior, tomando el valor devuelto de ese paso anterior.
Ejemplo:
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("foo");
}, 300);
});
myPromise
.then((value) => `${value} y barra`)
.then((value) => `${value} y barra de nuevo`)
.then((value) => `${value} y de nuevo`)
.then((value) => `${value} y de nuevo`)
.then((value) => {
console.log(value);
})
.catch((err) => {
console.error(err);
});
Nos devuelve:
En JavaScript se pueden agrupar promesas con Promise.all. Cuando tenga varias promesas similares podrá juntarlas y tratarlas como un grupo de promesas.Y cuando todas las promesas se resuelvan, Promise.all se resuelve y la salida es imprimirá.
Ejemplo:
const login = new Promise((resolve, reject) =>{
resolve('Your login is correct');
reject('Oops, bad login');
});
const greeting = new Promise((resolve, reject) => {
resolve('Hi, good morning');
reject('Error bad greeting.');
});
const Activities = Promise.all([login, greeting]);
Activities.then(res => {
res.forEach(activity => {console.log(activity);})
})
Nos devuelve:
En este último ejemplo res contendrá una matriz para que podamos simplemente llamar a la función forEach en ella. Se repetirá, activity es la variable de iteración, por lo que la primera vez será login. Y luego la segunda vez será el greeting. Y luego simplemente lo registramos en la consola. Esta es una forma de agrupar las promesas aprovechando todas las promesas para que su código sea más eficiente y más fácil de leer.
NOTA: Si una de las promesas falla, todo el resto de las promesas fallan. Entonces Promise.all es rechazado.
La forma general de consumir una promesa es utilizando el método .then() con un sólo parámetro, puesto que muchas veces lo único que nos interesa es realizar una acción cuando la promesa se cumpla. Lo que vemos en el ejemplo siguiente es el uso de la función fetch(), la cuál devuelve una promesa que se cumple cuando obtiene respuesta de la petición realizada. De esta forma, estaríamos preparando (de una forma legible) la forma de actuar de nuestro código a la respuesta de la petición realizada, todo ello de forma asíncrona.
Ejemplo:
fetch("/robots.txt").then(function(response) {
/* Código a realizar cuando se cumpla la promesa */
});
NOTA: Una fetch()promesa solo se rechaza cuando la solicitud falla, por ejemplo, debido a una URL de solicitud mal formada o a un error de red. Una fetch()promesa no se rechaza si el servidor responde con códigos de estado HTTP que indican errores ( 404, 504, etc.)
Recuerda que podemos hacer uso del método .catch() para actuar cuando se rechaza una promesa:
Ejemplo:
fetch("/robots.txt")
.then(function(response) {
/* Código a realizar cuando se cumpla la promesa */
})
.catch(function(error) {
/* Código a realizar cuando se rechaza la promesa */
});
📚REFERENCIAS:
https://www.arsys.es/blog/promesas-javascript#Como_se_crea_una_promesa_en_JavaScript
https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Global_Objects/Promise