Tengo una serie de promesas con las que estoy resolviendo Promise.all(arrayOfPromises);
Continúo para continuar la cadena de promesa. Se ve 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 catch para manejar una promesa individual en caso de que se produzca un 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 falló).
He intentado 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 dijeron las respuestas a continuación 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 servidor Express Node
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 capturar cualquier error de las promesas originales, pero luego devolver toda la matriz al siguiente.then
¡Gracias!
.then(function(data) { return data; })
puede omitirse por completothen
ocatch
hay un error que se arroja dentro. Por cierto, ¿es este nodo?Respuestas:
Promise.all
Es todo o nada. Se resuelve una vez que todas las promesas en la matriz se resuelven o rechazan 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 esperarí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í que su solución debería funcionar. Debe resolverse con una matriz que puede contener una combinación de valores exitosos y objetos de error. Es inusual pasar objetos de error en la ruta de éxito, pero suponiendo que su código los esté esperando, no veo ningún problema.
La única razón por la que puedo pensar por qué "no se resolvería" es que está fallando en el código que no nos está mostrando y la razón por la que no está viendo ningún mensaje de error al respecto es porque esta cadena de promesa no finaliza con un final atrapar (en cuanto a lo que nos está mostrando de todos modos).
Me tomé la libertad de descifrar 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 leen esto, es importante siempre devolver o terminar las cadenas, o los posibles errores, incluso los errores de codificación, se ocultarán (que es lo que sospecho que sucedió aquí):
fuente
Promise.allSettled()
con un soporte decente. Ver referencia .Promise.all
falla, cuando falla el primer hilo. Pero desafortunadamente, todos los otros subprocesos siguen funcionando hasta que terminan. Nada se cancela, peor aún: no hay forma de cancelar un hiloPromise
. Entonces, independientemente de lo que estén haciendo (y manipulando) los subprocesos, continúan, cambian estados y variables, usan CPU, pero al final no devuelven su resultado. Debe tener en cuenta esto para no producir un caos, por ejemplo, cuando repite / reintenta la llamada.NUEVA RESPUESTA
API FUTURE Promise
fuente
e
no tiene que ser unError
. Puede ser una cadena, por ejemplo, si alguien lo devuelve comoPromise.reject('Service not available')
..then()
y.catch()
.Promise.resolve()
pasaría valor al primero, mientras quePromise.reject()
lo pasará al segundo. Se puede envolver en objeto, por ejemplo:p.then(v => ({success: true, value: v})).catch(e => ({success: false, error: e}))
.Para continuar el
Promise.all
ciclo (incluso cuando una Promesa rechaza) escribí una función de utilidad que se llamaexecuteAllPromises
. Esta función de utilidad devuelve un objeto conresults
yerrors
.La idea es que todas las promesas que pases se
executeAllPromises
incluirán en una nueva promesa que siempre se resolverá. La nueva promesa se resuelve con una matriz que tiene 2 puntos. El primer punto contiene el valor de resolución (si lo hay) y el segundo lugar mantiene el error (si la promesa envuelta lo rechaza).Como paso final,
executeAllPromises
acumula todos los valores de las promesas envueltas y devuelve el objeto final con una matriz pararesults
y una matriz paraerrors
.Aquí está el código:
fuente
ES2020 presenta un nuevo método para el tipo de Promesa:
Promise.allSettled()
Promise.allSettled le da una señal cuando se liquidan todas las promesas de entrada, lo que significa que se cumplen o se rechazan. Esto es útil en 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.
Lea más en la publicación del blog v8 https://v8.dev/features/promise-combinators
fuente
Como @jib dijo:
Sin embargo, puede controlar ciertas promesas que están "permitidas" a fallar y nos gustaría continuar
.then
.Por ejemplo.
fuente
si puede usar la biblioteca q https://github.com/kriskowal/q tiene el método q.allSettled () que puede resolver este problema, puede manejar todas las promesas dependiendo de su estado, ya sea completo o rechazado.
fuente
q
), sería más útil si proporcionara un ejemplo de uso relacionado con la pregunta. Tal como está, su respuesta no explica cómo esta biblioteca puede ayudar a resolver el problema.Usando Async aguarde -
aquí una función asíncrona func1 está devolviendo un valor resuelto, y func2 arroja un error y devuelve un valor nulo en esta situación, podemos manejarlo como queremos y devolverlo en consecuencia.
La salida es - ['func1', null]
fuente
Para aquellos que usan ES8 que tropiezan aquí, pueden hacer algo como lo siguiente, usando funciones asíncronas :
fuente
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 usar los resultados restantes.Aquí he rechazado la primera promesa, por lo que es indefinida, pero podemos usar el resultado de la segunda promesa, que se encuentra en el índice 1.
fuente
¿Lo has considerado
Promise.prototype.finally()
?Parece estar diseñado para hacer exactamente lo que desea: ejecutar una función una vez que todas las promesas se hayan resuelto (resuelto / rechazado), independientemente de que algunas de las promesas sean rechazadas.
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 de su 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 finalmente no recibirá ningún argumento, ya que no hay medios confiables para determinar si la promesa se cumplió o rechazó. Este caso de uso es precisamente 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 undefined),Promise.resolve(2).finally(() => {})
se resolverá con 2. De manera similar, a diferencia dePromise.reject(3).then(() => {}, () => {})
(que se cumplirá con undefined),Promise.reject(3).finally(() => {})
se rechazará con 3.== Fallback ==
Si su versión de JavaScript no es compatible
Promise.prototype.finally()
, puede usar esta solución alternativa de Jake Archibald :Promise.all(promises.map(p => p.catch(() => undefined)));
fuente
Promises.allSettled()
se implemente realmente (está documentado por MDN aquí ), entoncesPromises.all.finally()
parecería lograr lo mismo. Estoy a punto de intentarlo ...allSettled()
.allSettled()
no está implementado en ninguna parte (todavía), por lo que no quiero adelantarme a la realidad. Tuve éxito conPromises.all(myPromiseArray).finally()
eso, y eso encaja con esta respuesta. Una vez queallSettled()
realmente exista, entonces podría probarlo y descubrir cómo funciona realmente. Hasta entonces, ¿quién sabe qué implementarán realmente los navegadores? A menos que tenga información reciente de lo contrario ...Promise.allSettled
no está implementado en Firefox, pero parece existir en Chrome. Solo porque los documentos dicen que está implementado no significa que realmente esté implementado. No lo voy a usar en el corto plazo.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 ejecuten, podría hacer algo como esto que se resolverá con las promesas de manera normal cuando todos tienen éxito y rechazan con las promesas fallidas cuando alguno de ellos falla:
fuente
Siempre puede ajustar sus funciones de devolución de promesas de manera que detecten el error y devuelvan en su lugar un valor acordado (por ejemplo, error.message), de modo que la excepción no llegue a la función Promise.all y la deshabilite.
fuente
He encontrado una manera (solución) para hacer esto sin hacer que se sincronice.
Entonces, como se mencionó anteriormente, no
Promise.all
es nada.entonces ... Use una promesa que lo encierra para atrapar y forzar la resolución.
fuente
Debería saber cómo identificar un error en sus resultados. Si no tiene un error esperado estándar, le sugiero que ejecute una transformación en cada error en el bloque catch que lo haga identificable en sus resultados.
fuente
No es la mejor manera de registrar el error, pero siempre puede configurar todo en una matriz para el promiseAll y almacenar los resultados resultantes en nuevas variables.
Si usa GraphQL, debe procesar la respuesta independientemente y si no encuentra la referencia correcta, bloqueará la aplicación, reduciendo el problema.
fuente
Así es como
Promise.all
está diseñado para funcionar. Si se trata de una sola promesareject()
, el método completo falla inmediatamente.Hay casos de uso en los que uno podría desear que las
Promise.all
promesas fracasen. Para que esto suceda, simplemente no use ningunareject()
declaración en su promesa. Sin embargo, para garantizar que su aplicación / script no se congele en caso de que alguna promesa subyacente nunca reciba una respuesta, debe ponerle un tiempo de espera.fuente
reject()
en su promesa está bien, pero ¿qué pasa si necesita usar las promesas de otra biblioteca?Escribí una biblioteca npm para lidiar con este problema más hermoso. https://github.com/wenshin/promiseallend
Instalar en pc
2017-02-25 nueva api, no es romper los principios de promesa
————————————————————————————————
Antigua mala API, ¡no la uses!
fuente
Promise.all
. Pero recopilará todos los datos y errores de cada promesa. También es compatible con la entrada de objetos, no es punto. Después de recopilar todos los datos y errores, anulo elpromise.then
método para tratar las devoluciones de llamada registradas que incluyen rechazado y cumplido. Para más detalles, puede ver el códigoonFulfilled
y a losonRejected
controladores que se pasanthen
?fulfilled
yrejected
. Pero realmente causa un problema difícil ser compatible con todos los casos de uso prometedores normalmente, comoonFulfilled
yonRejected
todos devuelvenPromise.reject()
oPromise.resolve()
. Hasta ahora no tengo claro cómo resolverlo, ¿alguien tiene una mejor idea? La mejor respuesta por ahora tiene un problema es que no puede filtrar datos y errores en el entorno del navegador.