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);
});