Tengo una serie de promesas con las que estoy resolviendo Promise.all(arrayOfPromises);
Continúo con la cadena de promesas. Parece algo como esto
existingPromiseChain = existingPromiseChain.then(function() {
var arrayOfPromises = state.routes.map(function(route){
return route.handler.promiseHandler();
});
return Promise.all(arrayOfPromises)
});
existingPromiseChain = existingPromiseChain.then(function(arrayResolved) {
// do stuff with my array of resolved promises, eventually ending with a res.send();
});
Quiero agregar una declaración de captura para manejar una promesa individual en caso de error, pero cuando lo intento, Promise.all
devuelve el primer error que encuentra (ignora el resto) y luego no puedo obtener los datos del resto de las promesas en la matriz (que no error).
Intenté hacer algo como ...
existingPromiseChain = existingPromiseChain.then(function() {
var arrayOfPromises = state.routes.map(function(route){
return route.handler.promiseHandler()
.then(function(data) {
return data;
})
.catch(function(err) {
return err
});
});
return Promise.all(arrayOfPromises)
});
existingPromiseChain = existingPromiseChain.then(function(arrayResolved) {
// do stuff with my array of resolved promises, eventually ending with a res.send();
});
Pero eso no se resuelve.
¡Gracias!
-
Editar:
Lo que las respuestas a continuación decían era completamente cierto, el código se estaba rompiendo debido a otras razones. En caso de que alguien esté interesado, esta es la solución con la que terminé ...
Cadena de servidores Node Express
serverSidePromiseChain
.then(function(AppRouter) {
var arrayOfPromises = state.routes.map(function(route) {
return route.async();
});
Promise.all(arrayOfPromises)
.catch(function(err) {
// log that I have an error, return the entire array;
console.log('A promise failed to resolve', err);
return arrayOfPromises;
})
.then(function(arrayOfPromises) {
// full array of resolved promises;
})
};
Llamada API (llamada route.async)
return async()
.then(function(result) {
// dispatch a success
return result;
})
.catch(function(err) {
// dispatch a failure and throw error
throw err;
});
Poner el .catch
for Promise.all
antes del .then
parece haber servido para detectar cualquier error de las promesas originales, pero luego devolver la matriz completa al siguiente.then
¡Gracias!
Promise.all
es todo o nada. Se resuelve una vez que se resuelven todas las promesas de la matriz, o se rechaza tan pronto como una de ellas rechaza. En otras palabras, se resuelve con una matriz de todos los valores resueltos o se rechaza con un solo error.
Algunas bibliotecas tienen algo llamado Promise.when
, que entiendo que en su lugar esperaría a que todas las promesas en la matriz se resuelvan o rechacen, pero no estoy familiarizado con eso y no está en ES6.
Tu codigo
Estoy de acuerdo con otros aquí en que su solución debería funcionar. Debería resolverse con una matriz que puede contener una combinación de valores correctos y objetos de error. Es inusual pasar objetos de error en la ruta de éxito, pero asumiendo que su código los está esperando, no veo ningún problema con eso.
La única razón por la que puedo pensar en por qué "no se resolvería" es porque está fallando en el código que no nos muestra y la razón por la que no ve ningún mensaje de error sobre esto es porque esta cadena de promesa no termina con un final captura (en cuanto a lo que nos estás mostrando de todos modos).
Me he tomado la libertad de descartar la "cadena existente" de su ejemplo y terminar la cadena con una trampa. Puede que esto no sea adecuado para usted, pero para las personas que lean esto, es importante siempre devolver o terminar cadenas, o los posibles errores, incluso los errores de codificación, se ocultarán (que es lo que sospecho que sucedió aquí):
Promise.all(state.routes.map(function(route) {
return route.handler.promiseHandler().catch(function(err) {
return err;
});
}))
.then(function(arrayOfValuesOrErrors) {
// handling of my array containing values and/or errors.
})
.catch(function(err) {
console.log(err.message); // some coding error in handling happened
});
NUEVA RESPUESTA
const results = await Promise.all(promises.map(p => p.catch(e => e)));
const validResults = results.filter(result => !(result instanceof Error));
API FUTURE Promise
ES2020 presenta un nuevo método para el tipo de Promesa: Promise.allSettled()
Promise.allSettled le da una señal cuando todas las promesas de entrada se cumplen, lo que significa que se cumplen o se rechazan. Esto es útil en los casos en los que no le importa el estado de la promesa, solo desea saber cuándo se realiza el trabajo, independientemente de si fue exitoso.
const promises = [
fetch('/api-call-1'),
fetch('/api-call-2'),
fetch('/api-call-3'),
];
// Imagine some of these requests fail, and some succeed.
const result = await Promise.allSettled(promises);
console.log(result.map(x=>x.status));
// ['fulfilled', 'fulfilled', 'rejected']
Lea más en la publicación del blog v8 https://v8.dev/features/promise-combinators
Para continuar el Promise.all
ciclo (incluso cuando se rechaza una Promesa) escribí una función de utilidad que se llama executeAllPromises
. Esta función de utilidad devuelve un objeto con results
y errors
.
La idea es que todas las promesas a las que pases executeAllPromises
estén envueltas en una nueva promesa que siempre se resolverá. La nueva Promesa se resuelve con una matriz que tiene 2 puntos. El primer lugar contiene el valor de resolución (si lo hay) y el segundo lugar mantiene el error (si la Promesa envuelta se rechaza).
Como paso final, executeAllPromises
acumula todos los valores de las promesas envueltas y devuelve el objeto final con una matriz para results
y una matriz para errors
.
Aquí está el código:
function executeAllPromises(promises) {
// Wrap all Promises in a Promise that will always "resolve"
var resolvingPromises = promises.map(function(promise) {
return new Promise(function(resolve) {
var payload = new Array(2);
promise.then(function(result) {
payload[0] = result;
})
.catch(function(error) {
payload[1] = error;
})
.then(function() {
/*
* The wrapped Promise returns an array:
* The first position in the array holds the result (if any)
* The second position in the array holds the error (if any)
*/
resolve(payload);
});
});
});
var errors = [];
var results = [];
// Execute all wrapped Promises
return Promise.all(resolvingPromises)
.then(function(items) {
items.forEach(function(payload) {
if (payload[1]) {
errors.push(payload[1]);
} else {
results.push(payload[0]);
}
});
return {
errors: errors,
results: results
};
});
}
var myPromises = [
Promise.resolve(1),
Promise.resolve(2),
Promise.reject(new Error('3')),
Promise.resolve(4),
Promise.reject(new Error('5'))
];
executeAllPromises(myPromises).then(function(items) {
// Result
var errors = items.errors.map(function(error) {
return error.message
}).join(',');
var results = items.results.join(',');
console.log(`Executed all ${myPromises.length} Promises:`);
console.log(`— ${items.results.length} Promises were successful: ${results}`);
console.log(`— ${items.errors.length} Promises failed: ${errors}`);
});
Como dijo @jib,
Promise.all
es todo o nada.
Sin embargo, puede controlar ciertas promesas que están "permitidas" para fallar y nos gustaría continuar .then
.
Por ejemplo.
Promise.all([
doMustAsyncTask1,
doMustAsyncTask2,
doOptionalAsyncTask
.catch(err => {
if( /* err non-critical */) {
return
}
// if critical then fail
throw err
})
])
.then(([ mustRes1, mustRes2, optionalRes ]) => {
// proceed to work with results
})
Usando Async await -
aquí una función asíncrona func1 está devolviendo un valor resuelto, y func2 está arrojando un error y devolviendo un nulo en esta situación, podemos manejarlo como queramos y regresar en consecuencia.
const callingFunction = async () => {
const manyPromises = await Promise.all([func1(), func2()]);
console.log(manyPromises);
}
const func1 = async () => {
return 'func1'
}
const func2 = async () => {
try {
let x;
if (!x) throw "x value not present"
} catch(err) {
return null
}
}
callingFunction();
La salida es - ['func1', null]
si puede usar la biblioteca q https://github.com/kriskowal/q tiene el método q.allSettled () que puede resolver este problema, puede manejar cada promesa dependiendo de su estado, ya sea completa o rechazada, por lo que
existingPromiseChain = existingPromiseChain.then(function() {
var arrayOfPromises = state.routes.map(function(route){
return route.handler.promiseHandler();
});
return q.allSettled(arrayOfPromises)
});
existingPromiseChain = existingPromiseChain.then(function(arrayResolved) {
//so here you have all your promises the fulfilled and the rejected ones
// you can check the state of each promise
arrayResolved.forEach(function(item){
if(item.state === 'fulfilled'){ // 'rejected' for rejected promises
//do somthing
} else {
// do something else
}
})
// do stuff with my array of resolved promises, eventually ending with a res.send();
});
Para aquellos que usan ES8 que tropiezan aquí, pueden hacer algo como lo siguiente, usando funciones asíncronas :
var arrayOfPromises = state.routes.map(async function(route){
try {
return await route.handler.promiseHandler();
} catch(e) {
// Do something to handle the error.
// Errored promises will return whatever you return here (undefined if you don't return anything).
}
});
var resolvedPromises = await Promise.all(arrayOfPromises);
Podemos manejar el rechazo a nivel de promesas individuales, por lo que cuando obtengamos los resultados en nuestra matriz de resultados, el índice de la matriz que ha sido rechazado será undefined
. Podemos manejar esa situación según sea necesario y utilizar los resultados restantes.
Aquí he rechazado la primera promesa, por lo que aparece como indefinida, pero podemos usar el resultado de la segunda promesa, que está en el índice 1.
const manyPromises = Promise.all([func1(), func2()]).then(result => {
console.log(result[0]); // undefined
console.log(result[1]); // func2
});
function func1() {
return new Promise( (res, rej) => rej('func1')).catch(err => {
console.log('error handled', err);
});
}
function func2() {
return new Promise( (res, rej) => setTimeout(() => res('func2'), 500) );
}
¿Lo has considerado Promise.prototype.finally()
?
Parece estar diseñado para hacer exactamente lo que usted desea: ejecutar una función una vez que todas las promesas se hayan establecido (resuelto / rechazado), independientemente de que algunas de las promesas se hayan rechazado.
De la documentación de MDN :
El finally()
método puede ser útil si desea realizar algún procesamiento o limpieza una vez que se cumpla la promesa, independientemente del resultado.
El finally()
método es muy similar a llamar, .then(onFinally, onFinally)
sin embargo, hay un par de diferencias:
Al crear una función en línea, puede pasarla una vez, en lugar de verse obligado a declararla dos veces o crear una variable para ella.
Una devolución de llamada final no recibirá ningún argumento, ya que no hay un medio confiable para determinar si la promesa se cumplió o se rechazó. Este caso de uso es precisamente para cuando no le importa el motivo del rechazo o el valor de cumplimiento, por lo que no es necesario proporcionarlo.
A diferencia Promise.resolve(2).then(() => {}, () => {})
(que se resolverá con indefinido), Promise.resolve(2).finally(() => {})
se resolverá con 2. Del mismo modo, a diferencia Promise.reject(3).then(() => {}, () => {})
(que se cumplirá con indefinido), Promise.reject(3).finally(() => {})
se rechazará con 3.
== Respaldo ==
Si su versión de JavaScript no es compatible Promise.prototype.finally()
, puede utilizar esta solución alternativa de Jake Archibald :Promise.all(promises.map(p => p.catch(() => undefined)));
En lugar de Promise.all, use Promise.allSettled, que espera a que se resuelvan todas las promesas, independientemente del resultado.
let p1 = new Promise(resolve => resolve("result1"));
let p2 = new Promise( (resolve,reject) => reject('some troubles') );
let p3 = new Promise(resolve => resolve("result3"));
// It returns info about each promise status and value
Promise.allSettled([p1,p2,p3]).then(result=> console.log(result));
Alternativamente, si tiene un caso en el que no le importan particularmente los valores de las promesas resueltas cuando hay una falla, pero aún desea que se hayan ejecutado, puede hacer algo como esto que se resolverá con las promesas normalmente cuando todos tienen éxito y rechazan las promesas fallidas cuando alguna de ellas falla:
function promiseNoReallyAll (promises) {
return new Promise(
async (resolve, reject) => {
const failedPromises = []
const successfulPromises = await Promise.all(
promises.map(
promise => promise.catch(error => {
failedPromises.push(error)
})
)
)
if (failedPromises.length) {
reject(failedPromises)
} else {
resolve(successfulPromises)
}
}
)
}
Siempre puede ajustar su promesa que devuelve funciones de manera que detecten fallas y, en su lugar, devuelvan un valor acordado (por ejemplo, error.message), de modo que la excepción no llegue hasta la función Promise.all y la deshabilite.
async function resetCache(ip) {
try {
const response = await axios.get(`http://${ip}/resetcache`);
return response;
}catch (e) {
return {status: 'failure', reason: 'e.message'};
}
}
Encontré una manera (solución alternativa) de hacer esto sin sincronizarlo.
Entonces, como se mencionó anteriormente, Promise.all
todo es ninguno.
así que ... Usa una promesa adjunta para atrapar y forzar la resolución.
let safePromises = originalPrmises.map((imageObject) => {
return new Promise((resolve) => {
// Do something error friendly
promise.then(_res => resolve(res)).catch(_err => resolve(err))
})
})
})
// safe
return Promise.all(safePromises)
Necesitaría saber cómo identificar un error en sus resultados. Si no tiene un error estándar esperado, le sugiero que ejecute una transformación en cada error en el bloque de captura que lo haga identificable en sus resultados.
try {
let resArray = await Promise.all(
state.routes.map(route => route.handler.promiseHandler().catch(e => e))
);
// in catch(e => e) you can transform your error to a type or object
// that makes it easier for you to identify whats an error in resArray
// e.g. if you expect your err objects to have e.type, you can filter
// all errors in the array eg
// let errResponse = resArray.filter(d => d && d.type === '<expected type>')
// let notNullResponse = resArray.filter(d => d)
} catch (err) {
// code related errors
}
No es la mejor forma de registrar errores, pero siempre puede configurar todo en una matriz para la promesa de todos y almacenar los resultados resultantes en nuevas variables.
Si usa graphQL, debe posprocesar la respuesta independientemente y si no encuentra la referencia correcta, bloqueará la aplicación, reduciendo dónde está el problema.
const results = await Promise.all([
this.props.client.query({
query: GET_SPECIAL_DATES,
}),
this.props.client.query({
query: GET_SPECIAL_DATE_TYPES,
}),
this.props.client.query({
query: GET_ORDER_DATES,
}),
]).catch(e=>console.log(e,"error"));
const specialDates = results[0].data.specialDates;
const specialDateTypes = results[1].data.specialDateTypes;
const orderDates = results[2].data.orders;
La estrella de HGTV, Christina Hall, revela que le diagnosticaron envenenamiento por mercurio y plomo, probablemente debido a su trabajo como manipuladora de casas.
Recientemente salió a la luz un informe policial que acusa a la estrella de 'Love Is Blind', Brennon, de violencia doméstica. Ahora, Brennon ha respondido a los reclamos.
Conozca cómo Wynonna Judd se dio cuenta de que ahora es la matriarca de la familia mientras organizaba la primera celebración de Acción de Gracias desde que murió su madre, Naomi Judd.
Descubra por qué un destacado experto en lenguaje corporal cree que es fácil trazar "tales paralelismos" entre la princesa Kate Middleton y la princesa Diana.
Los inodoros arrojan columnas de aerosol invisibles con cada descarga. ¿Como sabemos? La prueba fue capturada por láseres de alta potencia.
Air travel is far more than getting from point A to point B safely. How much do you know about the million little details that go into flying on airplanes?
The world is a huge place, yet some GeoGuessr players know locations in mere seconds. Are you one of GeoGuessr's gifted elite? Take our quiz to find out!
¿Sigue siendo efectivo ese lote de repelente de insectos que te quedó del verano pasado? Si es así, ¿por cuánto tiempo?
Si este tráiler de pesadilla de la temporada más reciente de Great British Bake Off te asustó y te hizo no volver a ver el programa, es posible que tengas suerte: PBS no ha decidido si se transmitirá o no la última temporada en los Estados Unidos. actualización, para aquellos que no siguen sin aliento este tipo de drama de nicho: el presentador Paul Hollywood y la hermosa carpa llena de batidoras de colores pastel y cuadros se trasladaron de la BBC al Canal 4; Mary Berry, Sue Perkins y Mel Giedroyc renunciaron.
Foto: Netflix Oh, Hello On Broadway (Netflix): Después de llegar a Broadway el año pasado, los dos locos del Upper West Side interpretados por John Mulaney y Nick Kroll finalmente llegaron a Netflix. El especial consta del espectáculo en el escenario, algunos momentos entre bastidores y un invitado muy especial de “Too Much Tuna”.
¿Quiere probar un cepillo de dientes Sonicare sin gastar mucho dinero en uno de sus modelos favoritos de gama alta? Puede comprar un kit de la Serie 2 o Serie 3 por tan solo $ 30 hoy en Amazon. Haga clic aquí para ver la lista completa de modelos elegibles y tenga en cuenta que se descontarán $ 10 adicionales en su carrito.
Tapas elásticas de silicona de Tomorrow's Kitchen, paquete de 12 | $14 | Amazonas | Código promocional 20OFFKINJALids son básicamente los calcetines de la cocina; siempre perdiéndose, dejando contenedores huérfanos que nunca podrán volver a cerrarse. Pero, ¿y si sus tapas pudieran estirarse y adaptarse a todos los recipientes, ollas, sartenes e incluso frutas en rodajas grandes que sobran? Nunca más tendrás que preocuparte por perder esa tapa tan específica.
El equipo está a la espera de las medallas que ganó en los Juegos Olímpicos de Invierno de 2022 en Beijing, ya que se está resolviendo un caso de dopaje que involucra a la patinadora artística rusa Kamila Valieva.
Miles de compradores de Amazon recomiendan la funda de almohada de seda Mulberry, y está a la venta en este momento. La funda de almohada de seda viene en varios colores y ayuda a mantener el cabello suave y la piel clara. Compre las fundas de almohada de seda mientras tienen hasta un 46 por ciento de descuento en Amazon
El jueves se presentó una denuncia de delito menor amenazante agravado contra Joe Mixon.
El Departamento de Policía de Lafayette comenzó a investigar a un profesor de la Universidad de Purdue en diciembre después de recibir varias denuncias de un "hombre sospechoso que se acercaba a una mujer".
Al igual que el mundo que nos rodea, el lenguaje siempre está cambiando. Mientras que en eras anteriores los cambios en el idioma ocurrían durante años o incluso décadas, ahora pueden ocurrir en cuestión de días o incluso horas.
Estoy de vuelta por primera vez en seis años. No puedo decirte cuánto tiempo he estado esperando esto.
“And a river went out of Eden to water the garden, and from thence it was parted and became into four heads” Genesis 2:10. ? The heart is located in the middle of the thoracic cavity, pointing eastward.
Creo, un poco tarde en la vida, en dar oportunidades a la gente. Generosamente.