w3schools then reject promises promesas nodejs ejemplo anidadas javascript node.js promise

then - promises javascript w3schools



Una forma limpia de esperar la primera verdad devuelta por Promesa (6)

Avanzando a partir de la respuesta de str, me gustaría agregar la capacidad de proporcionar una devolución de llamada, por lo que esto funciona en más de Promesas true/false .

Agregar una devolución de llamada permitirá probar el resultado de cualquier Promesa y devolver la promesa que coincida exitosamente con el filtro de devolución de llamada (que debería devolver un valor true/false ).

Promise.until = function(callback, ...promises) { return new Promise(function(resolve, reject) { promises.forEach(promise => promise.then(val => callback(val) === true && resolve(val)) ) }) } // Create some functions that resolve true/false function Promise1() {return new Promise(resolve => setTimeout(()=> resolve(false), 1000))} function Promise2() {return new Promise(resolve => setTimeout(()=> resolve(true), 3000))} function Promise3() {return new Promise(resolve => setTimeout(()=> resolve(false), 1000))} // Create som functions that resolve objects function Promise4() {return new Promise(resolve => setTimeout(()=> resolve({a:1}), 1000))} function Promise5() {return new Promise(resolve => setTimeout(()=> resolve({a:2}), 3000))} function Promise6() {return new Promise(resolve => setTimeout(()=> resolve({a:123}), 1000))} // Create some functions that resolve strings function Promise7() {return new Promise(resolve => setTimeout(()=> resolve(''Brass''), 1000))} function Promise8() {return new Promise(resolve => setTimeout(()=> resolve(''Monkey''), 500))} function Promise9() {return new Promise(resolve => setTimeout(()=> resolve([''Brass'', ''Monkey'']), 100))} // Once one resolves `true` we will catch it Promise.until(result => result === true, Promise1(), Promise2(), Promise3()) .then(result => console.log(result)); // Once one resolves where `a` equals 123, we will catch it Promise.until(result => result.a === 123, Promise4(), Promise5(), Promise6()) .then(result => console.log(result)); // Once one resolves where `a` equals 123, we will catch it Promise.until(result => result === ''Monkey'', Promise7(), Promise8(), Promise9()) .then(result => console.log(result));

Actualmente estoy trabajando en algo donde hago tres promesas en una matriz. Por el momento se ve algo como esto.

var a = await Promise.all([Promise1(), Promise2(), Promise3()]);

Ahora todas esas promesas volverán verdaderas o falsas. Pero en este momento estoy esperando a que todos terminen y podría continuar tan pronto como uno de ellos vuelva a ser verdadero.

Pensé en maneras de lograr eso pero todas parecían un poco feas. ¿Cómo resolverías esta tarea?


Básicamente quieres some() .

  • Promise.all() no funcionará porque te hará esperar a que se completen todas las Promesas.
  • Promise.race() solo no funcionará porque solo devuelve la resolución de 1 Promise.

En su lugar, necesitamos recibir un Array of Promises y seguir compitiendo hasta que uno de ellos se vuelva true en ese momento, debemos detenernos. Si ninguno de ellos es verdadero, todavía debemos detenernos, pero debemos tener en cuenta que ninguno de ellos fue verdadero.

Considere el siguiente ejemplo con arnés de prueba:

Código

/** * Promise aware setTimeout based on Angulars method * @param {Number} delay How long to wait before resolving * @returns {Promise} A resolved Promise to signal the timeout is complete */ function $timeout(delay) { return new Promise((resolve, reject) => { setTimeout(() => resolve(), delay); }); } /** * Return true (early) if any of the provided Promises are true * @param {Function(arg: *): Boolean} predicate The test the resolved Promise value must pass to be considered true * @param {Promise[]} arr The Promises to wait on * @returns {Promise<Boolean>} Whether one of the the provided Promises passed the predicate */ async function some(predicate, arr) { // Don''t mutate arguemnts const arrCopy = arr.slice(0); // Wait until we run out of Promises while(arrCopy.length){ // Give all our promises IDs so that we can remove them when they are done const arrWithIDs = arrCopy.map((p, idx) => p.then(data => ({idx, data}))); // Wait for one of the Promises to resolve const soon = await Promise.race(arrWithIDs); // If it passes the test, we''re done if(predicate(soon.data))return true; // Otherwise, remove that Promise and race again arrCopy.splice(soon.idx, 1); } // No Promises passed the test return false; } // Test harness const tests = [ function allTrue(){ console.log(new Date()); return some((v)=>v, [ $timeout(1000).then(() => true), $timeout(2000).then(() => true), $timeout(3000).then(() => true) ]).then(d => { console.log(d); console.log(new Date()); }); }, function twoSecondsTrue(){ console.log(new Date()); return some((v)=>v, [ $timeout(1000).then(() => false), $timeout(2000).then(() => true), $timeout(3000).then(() => true) ]).then(d => { console.log(d); console.log(new Date()); }); }, function threeSecondsTrue(){ console.log(new Date()); return some((v)=>v, [ $timeout(1000).then(() => false), $timeout(2000).then(() => false), $timeout(3000).then(() => true) ]).then(d => { console.log(d); console.log(new Date()); }); }, function allFalse(){ console.log(new Date()); return some((v)=>v, [ $timeout(1000).then(() => false), $timeout(2000).then(() => false), $timeout(3000).then(() => false) ]).then(d => { console.log(d); console.log(new Date()); }); } ] tests.reduce((acc, curr) => acc.then(()=>curr()), Promise.resolve());

Salida

// 1 Second true 2018-07-03T18:41:33.264Z true 2018-07-03T18:41:34.272Z // 2 Seconds true 2018-07-03T18:41:34.273Z true 2018-07-03T18:41:36.274Z // 3 Seconds true 2018-07-03T18:41:36.274Z true 2018-07-03T18:41:39.277Z // 3 Seconds false 2018-07-03T18:41:39.277Z false 2018-07-03T18:41:42.282Z


OK, dejaré la respuesta aceptada como está. Pero lo modifiqué un poco según mis necesidades, ya que pensé que este es un poco más fácil de leer y entender.

const firstTrue = Promises => { return new Promise((resolve, reject) => { // map each promise. if one resolves to true resolve the returned promise immidately with true Promises.map(p => { p.then(result => { if(result === true){ resolve(true); return; } }); }); // If all promises are resolved and none of it resolved as true, resolve the returned promise with false Promise.all(Promises).then(() => { resolve(Promises.indexOf(true) !== -1); }); }); }


Puede crear una nueva promesa que se resuelva tan pronto como una promesa determinada se resuelva de la siguiente manera:

function promiseRaceTrue(promises) { return new Promise(function(resolve, reject) { promises.forEach(promise => promise.then(val => val === true && resolve()) // TODO handle resolve with value of "false"? // TODO handle rejection? ); // TODO handle all resolved as "false"? }); } var a = await promiseRaceTrue([Promise1(), Promise2(), Promise3()]);

Se comporta de manera similar a Promise.race pero solo se resuelve si una de las promesas dadas se resuelve con el valor true lugar de resolverse tan pronto como cualquiera de las promesas dadas se resuelva o rechace.


Puede implementar esa combinación de Promise.race y Promise.all :

function firstTrue(promises) { const newPromises = promises.map(p => new Promise( (resolve, reject) => p.then(v => v && resolve(true), reject) )); newPromises.push(Promise.all(promises).then(() => false)); return Promise.race(newPromises); }

Prueba para el código anterior:

function firstTrue(promises) { const newPromises = promises.map(p => new Promise( (resolve, reject) => p.then(v => v && resolve(true), reject) )); newPromises.push(Promise.all(promises).then(() => false)); return Promise.race(newPromises); } var test = values => firstTrue( values.map((v) => new Promise((resolve) => { setTimeout(() => resolve(v), Math.round(Math.random() * 1000)); })) ).then((ret) => console.log(values, ret)); test([true, true, true]); test([false, false, false]); test([true, false, false]); test([false, true, false]); test([false, false, true]);


Puede usar Promise.race y solo resolver promesas iniciales cuando el valor es verdadero

const doSomething = (bool, val)=>{ return new Promise((resolve, reject)=>{ if (bool){ resolve(val) } }) } const promise1 = doSomething(false,''one'') const promise2 = doSomething(false,''two'') const promise3 = doSomething(true,''three'') const promise4 = doSomething(true,''four'') const promise5 = doSomething(true,''five'') Promise.race([promise1, promise2, promise3, promise4, promise5]).then(value => { console.log(''First true one to resolve is: '', value); });