Buen dia, Habr! Les presento la traducción del artículo
"Comprender las promesas en JavaScript" de Sukhjinder Arora.
Del autor de la traducción: Además del propio autor, espero que el artículo te haya sido útil. Por favor, si ella realmente te ayudó a aprender algo nuevo por ti mismo, ¡no seas demasiado vago para ir al artículo original y agradecer al autor! Estaré encantado de tus comentarios!
Enlace a la traducción del artículo sobre JavaScript asincrónico del mismo autor .JavaScript es un lenguaje de programación de un solo subproceso, lo que significa que se puede hacer una cosa a la vez. Antes de ES6, utilizamos devoluciones de llamada para administrar tareas asincrónicas, como la solicitud de red.
Usando promesas, podemos evitar el "infierno de devolución de llamada" y hacer que nuestro código sea más limpio, más legible y más fácil de entender.
Supongamos que queremos obtener algunos datos del servidor de forma asincrónica, utilizando devoluciones de llamada haríamos algo como esto:
getData(function(x){ console.log(x); getMoreData(x, function(y){ console.log(y); getSomeMoreData(y, function(z){ console.log(z); }); }); });
Aquí, solicito algunos datos del servidor utilizando la función
getData () , que recibe datos dentro de la función de devolución de llamada. Dentro de la función de devolución de llamada, solicito datos adicionales llamando a la función
getMoreData () , pasando los datos anteriores como argumento, y así sucesivamente.
Esto es lo que llamamos "infierno de devolución de llamada", donde cada devolución de llamada está anidada dentro de la otra, y cada devolución de llamada interna depende de su padre.
Podemos reescribir el fragmento anterior usando promesas:
getData() .then((x) => { console.log(x); return getMoreData(x); }) .then((y) => { console.log(y); return getSomeMoreData(y); }) .then((z) => { console.log(z); });
Puede ver lo que se ha vuelto más legible que con el primer ejemplo de devolución de llamada.
¿Qué son las promesas?
Una Promesa (Promesa) es un objeto que contiene el valor futuro de una operación asincrónica. Por ejemplo, si solicita algunos datos del servidor, Promis nos promete recibir estos datos, que podemos usar en el futuro.
Antes de sumergirnos en todas estas cosas técnicas, veamos la terminología de las promesas.
Estados de promesa
Una promesa en JavaScript, como una promesa en la vida real, tiene 3 estados. Esto puede ser 1) no resuelto (pendiente), 2) resuelto / resuelto (completado) o 3) rechazado / rechazado.
Sin resolver o pendiente : Promis espera si el resultado no está listo. Es decir, espera la finalización de algo (por ejemplo, la finalización de una operación asincrónica).
Resuelto o completado : Promis resuelto si el resultado está disponible. Es decir, algo completó su ejecución (por ejemplo, una operación asincrónica) y todo salió bien.
Rechazado : Promis rechazado si se produjo un error durante la ejecución.
Ahora que sabemos qué es Promis y su terminología, volvamos a la parte práctica de las promesas.
Crear promis
En la mayoría de los casos, simplemente usará promesas, no las creará, pero aún es importante saber cómo se crean.
Sintaxis:
const promise = new Promise((resolve, reject) => { ... });
Creamos una nueva promesa usando el constructor Promises, se necesita un argumento, una devolución de llamada, también conocida como una función ejecutiva, que toma 2 devoluciones de llamada,
resolver y
rechazar .
La función ejecutiva se realiza inmediatamente después de la creación de la promesa. Se hace una promesa al llamar a
resolve () , y se rechaza por
rechazar () . Por ejemplo:
const promise = new Promise((resolve, reject) => { if(allWentWell) { resolve(' !'); } else { reject('- '); } });
resolver () y
rechazar () toman un argumento, que puede ser una cadena, un número, una expresión lógica, una matriz o un objeto.
Echemos un vistazo a otro ejemplo para comprender completamente cómo se crean las promesas.
const promise = new Promise((resolve, reject) => { const randomNumber = Math.random(); setTimeout(() => { if(randomNumber < .6) { resolve(' !'); } else { reject('- '); } }, 2000); });
Aquí creé una nueva Promesa usando el constructor Promis. Una promesa se ejecuta o rechaza 2 segundos después de su creación. Se ejecuta una promesa si
randomNumber es menor que .6 y se rechaza en otros casos.
Cuando se ha creado una promesa, estará pendiente y su valor será
indefinido .
Después de 2 segundos, el temporizador finaliza, la promesa se ejecuta aleatoriamente o se rechaza, y su valor será el que se pasa a la función de
resolución o
rechazo . A continuación se muestra un ejemplo de dos casos:
Terminación exitosa:

Rechazo de promesa:
Nota: Promise se puede ejecutar o rechazar solo una vez. Las llamadas adicionales a
resolver () o
rechazar () no afectarán el estado de la promesa de ninguna manera. Un ejemplo:
const promise = new Promise((resolve, reject) => { resolve('Promise resolved');
Como se llamó primero a
resolve () , la promesa ahora tiene el estado "completado". La llamada posterior a
rechazar () no afectará el estado de la promesa de ninguna manera.
Usando Promis
Ahora sabemos cómo crear promesas, ahora veamos cómo aplicar la promesa ya creada. Usamos promesas usando los métodos
then () y
catch () .
Por ejemplo, consultar datos de una API usando
fetch , que devuelve una promesa.
.then () sintaxis: promise.then (successCallback, failureCallback)successCallback se llama si la promesa se ha ejecutado con éxito. Se necesita un argumento, que es el valor pasado para
resolver () .
failCallback se llama si la promesa ha sido rechazada. Se necesita un argumento, que es el valor dado a
rechazar () .
Un ejemplo:
const promise = new Promise((resolve, reject) => { const randomNumber = Math.random(); if(randomNumber < .7) { resolve(' !'); } else { reject(new Error('- ')); } }); promise.then((data) => { console.log(data);
Si se ejecutó la promesa, se
llama a
successCallback con el valor pasado para
resolver () . Y si la promesa fue rechazada, se
llama a
failureCallback con el valor pasado a rechazar ().
Sintaxis .catch () : promise.catch (failureCallback)Usamos
catch () para manejar errores. Esto es más legible que el manejo de errores dentro de
failureCallback dentro de la devolución de llamada del método
then () .
const promise = new Promise((resolve, reject) => { reject(new Error('- ')); }); promise .then((data) => { console.log(data); }) .catch((error) => { console.log(error);
Cadena de la promesa
Los métodos
then () y
catch () también pueden devolver una nueva promesa, que puede ser procesada por una cadena de otro then () al final del método anterior then ().
Usamos una cadena de promesas cuando queremos completar una secuencia de promesas.
Por ejemplo:
const promise1 = new Promise((resolve, reject) => { resolve('Promise1 '); }); const promise2 = new Promise((resolve, reject) => { resolve('Promise2 '); }); const promise3 = new Promise((resolve, reject) => { reject('Promise3 '); }); promise1 .then((data) => { console.log(data);
Entonces, ¿qué está pasando aquí?
Cuando
se cumple la
promesa1 , se llama al método
then (), que devuelve la promesa2.
Luego, cuando se
cumple la promesa2, se vuelve a
llamar a () y se devuelve la
promesa3 .
Como se rechaza la promesa3, en lugar de la siguiente
() , se llama a
catch () , que maneja el rechazo de la
promesa3 .
Nota: Como regla, un método
catch () es suficiente para manejar el rechazo de cualquiera de las promesas en la cadena, si este método está al final.
Error común
Muchos recién llegados cometen un error al invertir algunas promesas dentro de otras. Por ejemplo:
const promise1 = new Promise((resolve, reject) => { resolve('Promise1 '); }); const promise2 = new Promise((resolve, reject) => { resolve('Promise2 '); }); const promise3 = new Promise((resolve, reject) => { reject('Promise3 '); }); promise1.then((data) => { console.log(data);
Aunque esto funcionará bien, se considera un mal estilo y hace que el código sea menos legible. Si tiene una secuencia de promesas que ejecutar, será mejor ponerlas una tras otra que poner una dentro de la otra.
Promise.all ()
Este método toma una serie de promesas y devuelve una nueva promesa que se ejecutará cuando todas las promesas dentro de la matriz se ejecuten o rechacen tan pronto como se encuentre una promesa rechazada. Por ejemplo:
const promise1 = new Promise((resolve, reject) => { setTimeout(() => { resolve('Promise1 '); }, 2000); }); const promise2 = new Promise((resolve, reject) => { setTimeout(() => { resolve('Promise2 '); }, 1500); }); Promise.all([promise1, promise2]) .then((data) => console.log(data[0], data[1])) .catch((error) => console.log(error));
Aquí, el argumento dentro de
then () es una matriz que contiene los valores de las promesas en el mismo orden en que se pasaron a
Promise.all () . (Solo si se ejecutan todas las promesas)
La promesa se rechaza con la causa del rechazo de la primera promesa en la matriz transferida. Por ejemplo:
const promise1 = new Promise((resolve, reject) => { setTimeout(() => { resolve('Promise1 '); }, 2000); }); const promise2 = new Promise((resolve, reject) => { setTimeout(() => { reject('Promise2 '); }, 1500); }); Promise.all([promise1, promise2]) .then((data) => console.log(data[0], data[1])) .catch((error) => console.log(error));
Aquí tenemos dos promesas, donde una se ejecuta después de 2 segundos y la otra se desvía después de 1.5 segundos. Tan pronto como se rechaza la segunda promesa, la
promesa devuelta desde
Promise.all () se rechaza sin esperar la primera.
Este método puede ser útil cuando tiene más de una promesa y desea saber cuándo se han completado todas las promesas. Por ejemplo, si solicita datos de una API de terceros y desea hacer algo con estos datos solo cuando todas las solicitudes sean exitosas.
Como resultado, tenemos
Promise.all () , que espera la ejecución exitosa de todas las promesas, o completa su ejecución cuando detecta la primera falla en el conjunto de promesas.
Promise.race ()
Este método acepta una serie de promesas y devuelve una nueva promesa que se ejecutará tan pronto como se cumpla o rechace la promesa cumplida en la matriz si la promesa rechazada ocurre antes. Por ejemplo:
const promise1 = new Promise((resolve, reject) => { setTimeout(() => { resolve('Promise1 '); }, 1000); }); const promise2 = new Promise((resolve, reject) => { setTimeout(() => { reject('Promise2 '); }, 1500); }); Promise.race([promise1, promise2]) .then((data) => console.log(data))
Aquí tenemos dos promesas, donde una se ejecuta después de 1 segundo y la otra se desvía después de 1.5 segundos. Tan pronto como se cumpla la primera promesa, la promesa devuelta de Promise.race () tendrá el estado cumplido sin esperar el estado de la segunda promesa.
Aquí, los
datos que se pasan a
then () son el valor de la primera promesa ejecutada.
Como resultado,
Promise.race () espera la primera promesa y toma su estado como el estado de la promesa devuelta.
Comentario del autor de la traducción: De ahí el nombre mismo. Raza - RazaConclusión
Aprendimos qué son las promesas y qué comen en JavaScript. Las promesas consisten en dos partes 1) Crear una promesa y 2) Usar una promesa. La mayoría de las veces usará promesas en lugar de crearlas, pero es importante saber cómo se crean.
Eso es todo, ¡espero que este artículo te haya sido útil!