Explicación de las promesas de JavaScript

¿Qué es una promesa en JavaScript?

JavaScript es de un solo subproceso, lo que significa que dos bits de secuencia de comandos no se pueden ejecutar al mismo tiempo; tienen que correr uno tras otro. Una promesa es un objeto que representa la finalización final (o el fracaso) de una operación asincrónica y su valor resultante.

var promise = new Promise(function(resolve, reject) { // do thing, then… if (/* everything worked */) { resolve("See, it worked!"); } else { reject(Error("It broke")); } });

Existe una promesa en uno de estos estados

  • Pendiente: estado inicial, ni cumplido ni rechazado.
  • Cumplida: operación completada con éxito.
  • Rechazado: operación fallida.

El objeto Promise funciona como proxy de un valor que no se conoce necesariamente cuando se crea la promesa. Le permite asociar controladores con el valor eventual de éxito o la razón del fracaso de una acción asincrónica.

Esto permite que los métodos asincrónicos devuelvan valores como los métodos síncronos: en lugar de devolver inmediatamente el valor final, el método asincrónico devuelve una promesa de proporcionar el valor en algún momento en el futuro.

Usando 'Entonces' (Promise Chaining)

Para tomar varias llamadas asincrónicas y sincronizarlas una tras otra, puede usar el encadenamiento de promesas. Esto permite usar un valor de la primera promesa en devoluciones de llamada posteriores.

Promise.resolve('some') .then(function(string) { // <-- This will happen after the above Promise resolves (returning the value 'some') return new Promise(function(resolve, reject) { setTimeout(function() { string += 'thing'; resolve(string); }, 1); }); }) .then(function(string) { // <-- This will happen after the above .then's new Promise resolves console.log(string); // <-- Logs 'something' to the console });

API de promesa

Hay 4 métodos estáticos en la clase Promise:

  • Promise.resolve
  • Promise.reject
  • Promise.all
  • Promise.race

Las promesas se pueden encadenar

Al escribir Promesas para resolver un problema en particular, puede encadenarlas para formar la lógica.

var add = function(x, y) { return new Promise((resolve,reject) => { var sum = x + y; if (sum) { resolve(sum); } else { reject(Error("Could not add the two values!")); } }); }; var subtract = function(x, y) { return new Promise((resolve, reject) => { var sum = x - y; if (sum) { resolve(sum); } else { reject(Error("Could not subtract the two values!")); } }); }; // Starting promise chain add(2,2) .then((added) => { // added = 4 return subtract(added, 3); }) .then((subtracted) => { // subtracted = 1 return add(subtracted, 5); }) .then((added) => { // added = 6 return added * 2; }) .then((result) => { // result = 12 console.log("My result is ", result); }) .catch((err) => { // If any part of the chain is rejected, print the error message. console.log(err); });

Esto es útil para seguir un paradigma de programación funcional . Al crear funciones para manipular datos, puede encadenarlas para ensamblar un resultado final. Si en cualquier punto de la cadena de funciones se rechaza un valor, la cadena saltará al catch()controlador más cercano .

Para obtener más información sobre la programación funcional: Programación funcional

Generadores de funciones

En versiones recientes, JavaScript ha introducido más formas de manejar Promises de forma nativa. Una de esas formas es el generador de funciones. Los generadores de funciones son funciones "en pausa". Cuando se usa con Promises, los generadores pueden hacer que el uso sea mucho más fácil de leer y parecer "sincrónico".

const myFirstGenerator = function* () { const one = yield 1; const two = yield 2; const three = yield 3; return 'Finished!'; } const gen = myFirstGenerator();

Aquí está nuestro primer generador, que puede ver por la function*sintaxis. La genvariable que declaramos no se ejecutará myFirstGenerator, sino que "este generador está listo para usar".

console.log(gen.next()); // Returns { value: 1, done: false }

Cuando lo ponemos en funcionamiento gen.next(), se desconectará el generador y continuará. Dado que es la primera vez que llamamos gen.next(), se ejecutará yield 1y se detendrá hasta que volvamos a llamar gen.next(). Cuando yield 1sea ​​llamado, nos devolverá lo valueque se cedió y si el generador es o no done.

console.log(gen.next()); // Returns { value: 2, done: false } console.log(gen.next()); // Returns { value: 3, done: false } console.log(gen.next()); // Returns { value: 'Finished!', done: true } console.log(gen.next()); // Will throw an error

A medida que sigamos llamando gen.next(), continuará con la siguiente yieldy se detendrá cada vez. Una vez que no queden más yield, se procederá a ejecutar el resto del generador, que en este caso simplemente regresa 'Finished!'. Si gen.next()vuelve a llamar , arrojará un error cuando finalice el generador.

Ahora, imagine que si cada uno yielden este ejemplo fuera un Promise, el código en sí parecería extremadamente sincrónico.

Promise.all (iterable) es muy útil para múltiples solicitudes a diferentes fuentes

El método Promise.all (iterable) devuelve una sola Promise que se resuelve cuando todas las promesas del argumento iterable se han resuelto o cuando el argumento iterable no contiene promesas. Rechaza con la razón de la primera promesa que rechaza.

var promise1 = Promise.resolve(catSource); var promise2 = Promise.resolve(dogSource); var promise3 = Promise.resolve(cowSource); Promise.all([promise1, promise2, promise3]).then(function(values) { console.log(values); }); // expected output: Array ["catData", "dogData", "cowData"]

Más información sobre promesas:

  • Cómo funcionan realmente las promesas de JavaScript
  • Cómo implementar promesas en JavaScript
  • Cómo usar promesas en JavaScript
  • Cómo escribir una promesa de JavsScript