Comment puis-je accéder précédente promettent des résultats dans un .alors() de la chaîne?
J'ai restructuré mon code pour promesses, et construit un merveilleux long plat promesse de la chaîne d', constitué de multiples .then()
rappels. À la fin, je veux revenir à valeur composite, et la nécessité d'accéder à de multiples intermédiaire promettent des résultats. Cependant les valeurs de résolution à partir du milieu de la séquence ne sont pas dans le champ d'application dans le dernier rappel, comment puis-je y accéder?
function getExample() {
return promiseA(…).then(function(resultA) {
//Some processing
return promiseB(…);
}).then(function(resultB) {
//More processing
return //How do I gain access to resultA here?
});
}
Cette question est très intéressante, et même si il est étiqueté
Je viens de découvrir étaient toutes vos rep est d' 😉
javascript
, il est pertinent dans d'autres langues. Je viens d'utiliser le "briser la chaîne" réponse en java, et jdeferredJe viens de découvrir étaient toutes vos rep est d' 😉
OriginalL'auteur Bergi | 2015-01-31
Vous devez vous connecter pour publier un commentaire.
Briser la chaîne
Lorsque vous avez besoin d'accéder à des valeurs intermédiaires dans votre chaîne, vous devez diviser votre chaîne à part dans les pièces que vous avez besoin. Au lieu de fixer un rappel et d'une certaine manière en essayant d'utiliser son paramètre plusieurs fois, joindre plusieurs rappels à la même promesse, où vous avez besoin de la valeur du résultat. N'oubliez pas, un promesse juste représente (proxies) d'une valeur d'avenir! À côté de dériver une promesse de les autres dans une chaîne linéaire, utilisation de la promesse combinators qui vous sont données par votre bibliothèque pour construire la valeur du résultat.
Le résultat sera très simple de contrôle de flux, clair composition de fonctionnalités et donc facile modularisation.
À la place du paramètre déstructuration dans le rappel après
Promise.all
qui n'est devenue disponible avec ES6, dans l'ES5then
appel serait remplacé par un astucieux méthode d'aide qui a été fournie par de nombreux promesse bibliothèques (Q, Bluebird, lorsque, ...):.spread(function(resultA, resultB) { …
.Bluebird dispose également d'un dédié
join
function à remplacer quePromise.all
+spread
combinaison avec une plus simple (et plus efficace) construire:Il n'y a pas de fonctions dans le tableau, ce sont des promesses.
promiseA
etpromiseB
sont les (promesse-retour) fonctions ici.voici une démo jsfiddle.net/5t6L8dur
Jamais dit que c'était 🙂 Cette réponse a été écrit dans l'ES5 âge où aucune des promesses ont été dans la norme à tous, et
spread
a été super utile dans ce modèle. Pour plus de solutions modernes voir la accepté de répondre. Cependant, j'ai déjà mis à jour l'explicite-passthrough réponse, et il n'y a vraiment aucune bonne raison de ne pas mettre à jour celle-ci ainsi.Non, vous ne devriez pas faire ça, il apporterait des ennuis avec les rejets.
OriginalL'auteur Bergi
ECMAScript Harmonie
Bien sûr, ce problème a été reconnu par la langue de designers ainsi. Ils ont fait beaucoup de travail et de la async fonctions de proposition enfin dans
ECMAScript 8
Vous n'avez pas besoin d'un seul
then
invocation ou une fonction de rappel, comme dans un fonctions asynchrones (qui retourne une promesse lors de l'appelé), vous pouvez tout simplement attendre que les promesses de résoudre directement. Il dispose également d'arbitraire structures de contrôle comme des conditions, des boucles et des try-catch-clauses, mais pour des raisons de commodité, nous n'avons pas besoin d'eux ici:ECMAScript 6
Alors que nous étions en attente pour ES8, nous l'avons déjà fait dans le très même genre de syntaxe. ES6 est venu avec générateur de fonctions, qui permettent de rompre l'exécution à part en morceaux au arbitrairement placé
yield
mots-clés. Ces tranches peuvent être exécutés les uns après les autres, de façon indépendante, même de manière asynchrone, et c'est exactement ce que nous faisons lorsque nous voulons attendre pour une promesse de résolution avant d'exécuter l'étape suivante.Il y a consacré des bibliothèques (comme co ou task.js), mais aussi beaucoup de promesse de bibliothèques ont des fonctions d'assistance (Q, Bluebird, lorsque, ...) qui ne cette async étape-par-étape de l'exécution pour vous quand vous leur donnez un générateur de fonction que les rendements des promesses.
Ce n'travail dans Node.js depuis la version 4.0, qui est aussi un peu de navigateurs (ou leur dev éditions) ne le support de générateur de syntaxe relativement tôt.
ECMAScript 5
Toutefois, si vous voulez/besoin d'être rétro-compatible vous ne pouvez pas utiliser ceux sans transpiler. À la fois générateur de fonctions et async fonctions sont prises en charge par l'outillage actuel, voir, par exemple, la documentation de Babel sur générateurs et async fonctions.
Et puis, il y a aussi beaucoup d'autres compilation-à-JS langues
qui sont dédiés à l'amélioration de la programmation asynchrone. Généralement, ils utilisent une syntaxe similaire à
await
, (par exemple,Glacé CoffeeScript), mais il y a aussi d'autres qui disposent d'un Haskell-commedo
-notation (par exemple,LatteJs, monadique, PureScript ou LispyScript).avez-vous besoin d'attendre de la fonction async exemple getExample() de l'extérieur de code?
Oui,
getExample
est encore une fonction qui retourne une promesse, de travail tout comme les fonctions dans les autres réponses, mais avec plus agréables de la syntaxe. Vous pourriezawait
un appel dans une autreasync
de la fonction, ou vous pourriez chaîne.then()
à son résultat.Je suis curieux, pourquoi avez-vous répondu à votre propre question immédiatement après la poser? Il y a du bon débat ici, mais je suis curieux. Peut-être que vous avez trouvé vos réponses sur votre propre après avoir demandé?
J'ai posté l'ensemble de la discussion sur l'objet canonique double objectif
OriginalL'auteur Bergi
Synchrone inspection
Attribution promet pour plus tard-nécessaire-des valeurs à des variables et leur valeur via synchrone de l'inspection. L'exemple utilise bluebird est
.value()
méthode, mais de nombreuses bibliothèques offrent la même méthode.Ceci peut être utilisé pour toutes les valeurs que vous aimez:
Euh, "un minimum de confiance sur les fonctionnalités de la bibliothèque"? Synchrone d'inspection est une fonction de bibliothèque, et un assez standard pour démarrer.
Je crois qu'il voulait de la bibliothèque de fonctions spécifiques
OriginalL'auteur Esailija
De nidification (et), les fermetures
À l'aide de fermetures pour le maintien de la portée des variables (dans notre cas, le succès de rappel des paramètres de fonction) est la solution d'activer JavaScript. Avec des promesses, nous pouvons arbitrairement nid et les aplatir
.then()
rappels - ils sont sémantiquement équivalents, sauf pour le champ d'application de l'intérieure.Bien sûr, c'est la construction d'une indentation de la pyramide. Si l'indentation est trop grande, vous pouvez toujours appliquer les vieux instruments pour lutter contre la pyramide de doom: modulariser, utiliser des fonctions nommées, et les aplatir la promesse de la chaîne dès que vous n'avez pas besoin d'une variable de plus.
En théorie, vous pouvez toujours éviter de plus de deux niveaux d'imbrication (en faisant toutes les fermetures explicite), dans la pratique, utiliser autant que raisonnable.
Vous pouvez également utiliser des fonctions d'assistance pour ce genre de l'application partielle, comme
_.partial
de Trait de soulignement/lodash ou la natif.bind()
méthode, de diminuer encore l'indentation:C'est exactement le
bind
fonction dans les Monades. Haskell fournit sucre syntaxique (do-notation) pour la faire ressembler à async/await syntaxe.Agréable lecture! Le motif est tout à fait lisible et a été d'une grande aide. Merci!!!!
OriginalL'auteur Bergi
Explicite pass-through
Similaire à l'imbrication des callbacks, cette technique s'appuie sur les fermetures. Pourtant, la chaîne reste plat au lieu de transmettre uniquement le dernier résultat, de l'état de l'objet est passé à chaque étape. Ces objets s'accumulent les résultats des actions précédentes, la transmission de toutes les valeurs qui seront nécessaires plus tard encore, plus le résultat de la tâche en cours.
Ici, dans cette petite flèche
b => [resultA, b]
est la fonction qui se referme surresultA
, et passe un tableau des résultats à l'étape suivante. Qui utilise le paramètre de déstructuration de la syntaxe à la décomposer dans des variables simples de nouveau.Avant de déstructuration est disponible avec ES6, une chouette helper méthode appelée
.spread()
a été fourni par de nombreux promesse bibliothèques (Q, Bluebird, lorsque, ...). Elle prend une fonction avec plusieurs paramètres - un pour chaque élément du tableau - être utilisé comme.spread(function(resultA, resultB) { …
.Bien sûr, que la fermeture nécessaire ici peut encore être simplifiée par des fonctions d'aide, par exemple,
Alternativement, vous pouvez utiliser
Promise.all
pour produire de la promesse pour le tableau:Et vous risquez de ne pas seulement utiliser des tableaux, mais arbitrairement des objets complexes. Par exemple, avec
_.étendre
oude l'Objet.attribuer
dans une autre fonction d'assistance:Alors que ce modèle garantit une télévision et de la chaîne d'explicite de l'état des objets peuvent améliorer la clarté, il va devenir fastidieux pour une longue chaîne. Surtout quand vous avez besoin de l'état que de façon sporadique, vous avez encore à passer à travers chaque étape. Avec cette interface fixe, le seul rappels de la chaîne sont assez étroitement couplé et rigides à changer. Il fait l'affacturage unique étapes les plus difficiles, et des rappels de service ne peut être fourni directement à partir d'autres modules - ils ont toujours besoin d'être enveloppé dans du code réutilisable qui se soucie de l'état. Résumé des fonctions d'assistance comme ci-dessus peuvent soulager la douleur un peu, mais il sera toujours présent.
Promise.all
devraient être encouragés (il ne fonctionnera pas dans l'ES6 lors de la déstructuration la remplacera et de la commutation d'une.spread
à unthen
donne souvent des résultats inattendus. Comme d'augmenter - je ne suis pas sûr pourquoi vous devez utiliser augmenter - ajouter des choses à la promesse prototype n'est pas une manière acceptable de prolonger ES6 promet quand même qui sont censés être étendu avec (actuellement non pris en charge) sous-classement.Qu'entendez-vous par "la syntaxe de l'omission
Promise.all
"? Aucune de ces méthodes dans cette réponse permettra de rompre avec l'ES6. La commutation d'unspread
à une déstructurationthen
ne devrait pas avoir de problèmes. Re .le prototype.augmenter: je savais que quelqu'un serait-il un avis, j'ai juste aimé pour explorer les possibilités pour l'éditer.Par la syntaxe de tableau je veux dire
return [x,y]; }).spread(...
au lieu dereturn Promise.all([x, y]); }).spread(...
qui ne changerait pas lors de la permutation de propagation pour es6 déstructuration de sucre et aussi de ne pas être un drôle de cas limite où les promesses de traiter le retour des tableaux différemment de tout le reste.C'est probablement la meilleure réponse. Les promesses sont "Fonctionnel Réactif de Programmation"-la lumière, et c'est souvent la solution employée. Par exemple, BaconJs, a #combineTemplate qui vous permet de combiner les résultats dans un objet qui passe en bas de la chaîne
La réponse a été écrit lors de l'ES6 n'était pas aussi répandue qu'elle est aujourd'hui. Ouais, peut-être il est temps pour échanger les exemples
OriginalL'auteur Bergi
Mutable contextuel de l'état
Le trivial (mais peu élégante et plutôt susceptible de causer des erreurs) la solution est d'utiliser le plus-portée des variables (à laquelle tous les rappels dans la chaîne d'accès) et d'écrire des valeurs de résultat à eux quand vous les obtenez:
Au lieu de beaucoup de variables, on peut également utiliser un (initialement vide) de l'objet, sur lequel les résultats sont stockés en tant que de créer dynamiquement des propriétés.
Cette solution présente plusieurs inconvénients:
Le Bluebird bibliothèque encourage l'utilisation d'un objet qui est transmis le long, en utilisant leur
bind()
méthode pour affecter un objet de contexte à une promesse de la chaîne. Il sera accessible à partir de chaque fonction de rappel via le inutilisablethis
mot clé. Tandis que les propriétés de l'objet sont plus enclins à inaperçue fautes de frappe que sur des variables, le modèle est assez astucieux:Cette approche peut être facilement simulé dans la promesse des bibliothèques qui ne prennent pas en charge .bind (bien que de façon un peu plus verbeux et ne peut pas être utilisée dans une expression):
.bind()
est inutile pour la prévention de la fuite de mémoireMais il n'est pas retourné avec la promesse de maintenir une référence à l'objet de contexte autrement? OK, bien sûr, la collecte des ordures s'en occupera plus tard; ce n'est pas une "fuite" à moins que la promesse n'est jamais disposé.
Oui, mais il promet aussi de tenir référence à leur épanouissement des valeurs et de l'erreur de raisons... mais rien ne fait référence à la promesse de sorte qu'il n'a pas d'importance
Merci de briser cette réponse en deux que j'ai failli voté sur le préambule! Je pense que "le trivial (mais peu élégante et plutôt susceptible de causer des erreurs) solution" est la plus propre et la solution la plus simple, puisqu'il s'appuie pas plus sur les fermetures et mutable état de votre auto-réponse, est encore plus simple. Les fermetures sont ni global, ni le mal. Les arguments à l'encontre de cette approche n'ont pas de sens pour moi, compte tenu de la prémisse. Ce que la modularisation des problèmes, il peut être donné un "merveilleux plat de la promesse de la chaîne"?
Comme je l'ai dit ci-dessus, les Promesses sont "Fonctionnel Réactif de Programmation"-lumière. C'est un anti-modèle en PRF
OriginalL'auteur Bergi
Un moins rude spin sur "Mutable contextuel de l'état"
À l'aide d'un localement étendue de l'objet de recueillir les résultats intermédiaires d'une promesse de la chaîne est une approche raisonnable à la question que vous avez posée. Considérons l'extrait suivant:
Promise
constructeur antipattern!Merci @Bergi, je ne savais même pas que c'était un anti-modèle jusqu'à ce que vous avez mentionné qu'il!
c'est une bonne solution pour atténuer la promesse d'erreur lié.J'ai été en utilisant ES5 et ne voulez pas ajouter une autre bibliothèque pour travailler avec la promesse.
OriginalL'auteur Jay
Nœud 7.4 prend désormais en charge async/await appels avec l'harmonie du pavillon.
Essayez ceci:
et exécutez le fichier avec:
node --harmony-async-await getExample.js
Simple que peut l'être!
OriginalL'auteur Antoine
Une autre réponse, à l'aide de
babel-node
version <6À l'aide de
async - await
npm install -g [email protected]
example.js:
Ensuite, exécutez
babel-node example.js
et le tour est joué!Oui je l'ai fait, juste après avoir posté le mien. Encore, je vais le laisser, car elle explique comment obtenir en place et fonctionne avec l'aide de ES7 plutôt que de simplement dire qu'un jour, ES7 seront disponibles.
Ah oui, je devrais mettre à jour ma réponse à-dire que le "expérimentale" des plugins pour ces déjà ici.
OriginalL'auteur Antoine
À ce jours, j'ai aussi hava répondre à certaines questions comme vous. Enfin, j'ai trouvé une bonne solution avec les quesition, c'est simple et bon à lire. J'espère que cela peut vous aider.
Selon comment-à-chaîne-javascript-promesses
ok, regardons le code:
Chaque promesse de la valeur précédente, quelle est votre sens?
Jetez un oeil sur le code en question. Le but n'est pas d'obtenir le résultat de la promesse que
.then
est appelée, mais les résultats de avant que. E. g.thirdPromise
accéder à la suite defirstPromise
.Désolé, je sais que votre sens maintenant, c'est ma première réponse sur stackoverflow, veuillez pardonner.
Le vôtre est une excellente idée! qui peuvent aider à la construction de tous les résultats. Continuez à avancer.
OriginalL'auteur yzfdjzwl
Je ne vais pas utiliser ce modèle dans mon code car je ne suis pas un grand fan de l'utilisation de variables globales. Cependant, dans un pincement cela va fonctionner.
Utilisateur est un promisified Mangouste modèle.
Dans votre cas, le motif semble être inutile si. Vous n'avez pas besoin d'un
globalVar
à tous, il suffit de faireUser.findAsync({}).then(function(users){ console.log(users); mongoose.connection.close() });
?Je n'ai pas besoin personnellement dans mon propre code, mais l'utilisateur peut avoir besoin de courir plus async dans la seconde fonction et ensuite interagir avec la Promesse d'origine de l'appel. Mais comme mentionné, je vais être à l'aide de générateurs dans ce cas. 🙂
OriginalL'auteur Antoine
Lors de l'utilisation de bluebird, vous pouvez utiliser
.bind
méthode pour partager des variables dans la promesse de la chaîne:veuillez consulter ce lien pour plus d'informations:
http://bluebirdjs.com/docs/api/promise.bind.html
OriginalL'auteur alphakevin
moyen facile 😀
OriginalL'auteur Minh Giang
Je pense que vous pouvez utiliser hachage de RSVP.
Quelque chose comme ci-dessous :
Promise.all
solution, seulement avec un objet au lieu d'un tableau.OriginalL'auteur Vishu