J'ai un éventail de promesses avec lesquelles je résous Promise.all(arrayOfPromises);
Je continue la chaîne de promesses. Ressemble à quelque chose comme ça
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();
});
Je veux ajouter une instruction catch pour gérer une promesse individuelle en cas d'erreur, mais lorsque j'essaie, Promise.all
renvoie la première erreur trouvée (ignore le reste), puis je ne peux pas obtenir les données du reste des promesses dans le tableau (qui n'a pas fait d'erreur).
J'ai essayé de faire quelque chose comme ..
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();
});
Mais cela ne résout pas.
Merci!
-
Éditer:
Ce que les réponses ci-dessous ont dit était complètement vrai, le code cassait pour d'autres raisons. Si quelqu'un est intéressé, c'est la solution avec laquelle je me suis retrouvé ...
Chaîne de serveurs 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;
})
};
Appel API (appel route.async)
return async()
.then(function(result) {
// dispatch a success
return result;
})
.catch(function(err) {
// dispatch a failure and throw error
throw err;
});
Mettre le .catch
for Promise.all
avant le .then
semble avoir permis de détecter les erreurs des promesses originales, mais de renvoyer ensuite l'ensemble du tableau au suivant.then
Merci!
.then(function(data) { return data; })
peut être complètement omisthen
oucatch
et qu'une erreur est générée à l'intérieur. Soit dit en passant, est ce nœud?Réponses:
Promise.all
c'est tout ou rien. Il résout une fois que toutes les promesses du tableau sont résolues, ou rejetées dès que l' une d'elles rejette. En d'autres termes, il résout soit avec un tableau de toutes les valeurs résolues, soit il rejette avec une seule erreur.Certaines bibliothèques ont quelque chose appelé
Promise.when
, qui, à ma connaissance, attendrait toutes les promesses du tableau à résoudre ou à rejeter, mais je ne le connais pas et ce n'est pas dans ES6.Votre code
Je suis d'accord avec les autres ici que votre solution devrait fonctionner. Il doit être résolu avec un tableau qui peut contenir un mélange de valeurs réussies et d'objets erreurs. Il est inhabituel de passer des objets d'erreur dans le chemin de réussite, mais en supposant que votre code les attend, je ne vois aucun problème avec cela.
La seule raison pour laquelle je peux penser pourquoi cela "ne résoudrait pas" est qu'il échoue dans le code que vous ne nous montrez pas et que vous ne voyez aucun message d'erreur à ce sujet parce que cette chaîne de promesses n'est pas terminée par un final attraper (autant que ce que vous nous montrez de toute façon).
J'ai pris la liberté de factoriser la "chaîne existante" de votre exemple et de terminer la chaîne avec un crochet. Cela ne vous convient peut-être pas, mais pour les personnes qui lisent ceci, il est important de toujours renvoyer ou terminer les chaînes, sinon les erreurs potentielles, même les erreurs de codage, seront masquées (ce qui, je suppose, s'est produit ici):
la source
Promise.allSettled()
avec un support décent. Voir référence .Promise.all
échoue, lorsque le premier thread échoue. Mais malheureusement, tous les autres threads continuent de fonctionner jusqu'à ce qu'ils se terminent. Rien n'est annulé, pire encore: il n'y a aucun moyen d'annuler un threadPromise
. Donc, quoi que les threads fassent (et manipulent), ils continuent, ils changent les états et les variables, ils utilisent le CPU, mais à la fin ils ne retournent pas leur résultat. Vous devez en être conscient pour ne pas créer de chaos, par exemple lorsque vous répétez / réessayez l'appel.NOUVELLE RÉPONSE
API FUTURE Promise
la source
e
ne doit pas nécessairement être unError
. Il peut s'agir d'une chaîne, par exemple, si quelqu'un la renvoie commePromise.reject('Service not available')
..then()
et.catch()
.Promise.resolve()
transmettrait de la valeur à la première, tandisPromise.reject()
qu'elle la transmettrait à la seconde. Vous pouvez les envelopper dans l' objet , par exemple:p.then(v => ({success: true, value: v})).catch(e => ({success: false, error: e}))
.Pour continuer la
Promise.all
boucle (même lorsqu'une promesse refuse), j'ai écrit une fonction utilitaire qui est appeléeexecuteAllPromises
. Cette fonction utilitaire renvoie un objet avecresults
eterrors
.L'idée est que toutes les promesses auxquelles vous passez
executeAllPromises
seront enveloppées dans une nouvelle promesse qui sera toujours résolue. La nouvelle promesse se résout avec un tableau qui a 2 spots. Le premier emplacement contient la valeur de résolution (le cas échéant) et le second emplacement conserve l'erreur (si la promesse encapsulée rejette).Comme étape finale, le
executeAllPromises
accumule toutes les valeurs des promesses encapsulées et retourne l'objet final avec un tableau pourresults
et un tableau pourerrors
.Voici le code:
la source
ES2020 introduit une nouvelle méthode pour le type de promesse:
Promise.allSettled()
Promise.allSettled vous donne un signal lorsque toutes les promesses d'entrée sont réglées, ce qui signifie qu'elles sont remplies ou rejetées. Ceci est utile dans les cas où vous ne vous souciez pas de l'état de la promesse, vous voulez simplement savoir quand le travail est terminé, qu'il ait réussi ou non.
En savoir plus dans le blog v8 https://v8.dev/features/promise-combinators
la source
Comme l'a dit @jib,
Cependant, vous pouvez contrôler certaines promesses qui sont "autorisées" à échouer et nous aimerions continuer
.then
.Par exemple.
la source
si vous arrivez à utiliser la bibliothèque q https://github.com/kriskowal/q, elle dispose de la méthode q.allSettled () qui peut résoudre ce problème, vous pouvez gérer chaque promesse en fonction de son état soit complet, soit rejeté, donc
la source
q
), il serait plus utile de fournir un exemple d'utilisation lié à la question. En l'état, votre réponse n'explique pas comment cette bibliothèque peut aider à résoudre le problème.Utilisation d'Async wait -
ici, une fonction asynchrone func1 renvoie une valeur résolue, et func2 renvoie une erreur et renvoie une valeur nulle dans cette situation, nous pouvons la gérer comme nous le voulons et retourner en conséquence.
La sortie est - ['func1', null]
la source
Pour ceux qui utilisent ES8 qui trébuchent ici, vous pouvez faire quelque chose comme ceci, en utilisant des fonctions asynchrones :
la source
Nous pouvons gérer le rejet au niveau des promesses individuelles, donc lorsque nous obtenons les résultats dans notre tableau de résultats, l'index du tableau qui a été rejeté sera
undefined
. Nous pouvons gérer cette situation au besoin et utiliser les résultats restants.Ici, j'ai rejeté la première promesse, elle est donc indéfinie, mais nous pouvons utiliser le résultat de la deuxième promesse, qui est à l'index 1.
la source
Avez-vous réfléchi
Promise.prototype.finally()
?Il semble être conçu pour faire exactement ce que vous voulez - exécuter une fonction une fois que toutes les promesses ont été réglées (résolues / rejetées), indépendamment de certaines des promesses rejetées.
De la documentation MDN :
La
finally()
méthode peut être utile si vous souhaitez effectuer un traitement ou un nettoyage une fois la promesse réglée, quel que soit son résultat.La
finally()
méthode est très similaire à l'appel,.then(onFinally, onFinally)
mais il existe quelques différences:Lors de la création d'une fonction en ligne, vous pouvez la transmettre une fois, au lieu d'être obligé de la déclarer deux fois ou de créer une variable pour elle.
Un rappel final ne recevra aucun argument, car il n'existe aucun moyen fiable de déterminer si la promesse a été tenue ou rejetée. Ce cas d'utilisation est précisément lorsque vous ne vous souciez pas de la raison du rejet ou de la valeur de réalisation, et il n'est donc pas nécessaire de le fournir.
Contrairement à
Promise.resolve(2).then(() => {}, () => {})
(qui sera résolu avec undefined),Promise.resolve(2).finally(() => {})
sera résolu avec 2. De même, contrairement àPromise.reject(3).then(() => {}, () => {})
(qui sera rempli avec undefined),Promise.reject(3).finally(() => {})
sera rejeté avec 3.== Repli ==
Si votre version de JavaScript ne prend pas en charge,
Promise.prototype.finally()
vous pouvez utiliser cette solution de contournement de Jake Archibald :Promise.all(promises.map(p => p.catch(() => undefined)));
la source
Promises.allSettled()
soit réellement implémenté (c'est documenté par MDN ici ), alorsPromises.all.finally()
il semblerait que la même chose soit accomplie. Je suis sur le point d'essayer ...allSettled()
.allSettled()
n'est pas implémenté nulle part (encore), donc je ne veux pas prendre de l'avance sur la réalité. J'ai eu du succès avecPromises.all(myPromiseArray).finally()
, et cela correspond à cette réponse. Une foisallSettled()
qu'il existe réellement, je pourrais le tester et découvrir comment cela fonctionne réellement. D'ici là, qui sait ce que les navigateurs implémenteront réellement? Sauf si vous avez des informations récentes à l'effet contraire ...Promise.allSettled
n'est pas implémenté dans Firefox, mais il semble exister dans Chrome. Ce n'est pas parce que les documents disent qu'il est implémenté qu'il est vraiment implémenté. Je ne vais pas l'utiliser de sitôt.Alternativement, si vous avez un cas où vous ne vous souciez pas particulièrement des valeurs des promesses résolues quand il y a un échec mais que vous voulez toujours qu'elles se soient déroulées, vous pouvez faire quelque chose comme ça qui résoudra les promesses normalement lorsque ils réussissent tous et rejettent avec les promesses manquées quand l'un d'eux échoue:
la source
Vous pouvez toujours envelopper vos fonctions de retour de promesse d'une manière qui attrape l'échec et renvoie à la place une valeur convenue (par exemple error.message), de sorte que l'exception ne sera pas transférée jusqu'à la fonction Promise.all et la désactiver.
la source
J'ai trouvé un moyen (solution de contournement) de le faire sans le synchroniser.
Donc, comme cela a été mentionné précédemment
Promise.all
tout est nul.alors ... Utilisez une promesse englobante pour attraper et forcer la résolution.
la source
Vous devez savoir comment identifier une erreur dans vos résultats. Si vous n'avez pas d'erreur standard attendue, je vous suggère d'exécuter une transformation sur chaque erreur dans le bloc catch qui la rend identifiable dans vos résultats.
la source
Ce n'est pas le meilleur moyen de consigner les erreurs, mais vous pouvez toujours tout définir sur un tableau pour promiseAll et stocker les résultats résultants dans de nouvelles variables.
Si vous utilisez graphQL, vous devez malgré tout post-traiter la réponse et si elle ne trouve pas la référence correcte, l'application se bloquera, ce qui réduira l'emplacement du problème.
la source
Voilà comment
Promise.all
est conçu pour fonctionner. Si une seule promesse est faitereject()
, la méthode entière échoue immédiatement.Il existe des cas d'utilisation où l'on peut souhaiter que les
Promise.all
promesses échouent. Pour ce faire, n'utilisez simplement aucunereject()
déclaration dans votre promesse. Cependant, pour vous assurer que votre application / script ne se fige pas au cas où une seule promesse sous-jacente n'obtiendrait jamais de réponse, vous devez y mettre un délai d'attente.la source
reject()
dans votre promesse est bien, mais que faire si vous avez besoin d'utiliser les promesses d'une autre bibliothèque?J'ai écrit une bibliothèque npm pour faire face à ce problème plus beau. https://github.com/wenshin/promiseallend
Installer
2017-02-25 nouvelle API, ce n'est pas rompre les principes de la promesse
————————————————————————————————
Vieille mauvaise api, ne l'utilisez pas!
la source
Promise.all
. Mais il collectera toutes les données et les erreurs de chaque promesse. il prend également en charge la saisie d'objets, ce n'est pas un point. après avoir collecté toutes les données et les erreurs, je remplace lapromise.then
méthode pour traiter les rappels enregistrés, notamment rejetés et satisfaits. Pour plus de détails, vous pouvez voir le codeonFulfilled
et lesonRejected
gestionnaires qui sont passés àthen
?fulfilled
etrejected
. Mais en réalité, cela cause un problème difficile à être compatible avec tous les cas d'utilisation de promesse normalement, commeonFulfilled
etonRejected
tout retourPromise.reject()
ouPromise.resolve()
. Jusqu'à présent, je ne sais pas comment le résoudre, quelqu'un a-t-il une meilleure idée? La meilleure réponse pour l'instant a un problème, c'est qu'il ne peut pas filtrer les données et les erreurs dans l'environnement du navigateur.