web-dev-qa-db-fra.com

Comment extraire des données d'une promesse

J'ai une promesse qui renvoie des données et je veux l'enregistrer dans des variables. Est-ce impossible en JavaScript en raison de la nature asynchrone et dois-je utiliser onResolve comme rappel?

Puis-je utiliser cela en quelque sorte (par exemple, envelopper avec async/wait):

const { foo, bar } = Promise.then(result => result.data, errorHandler);
// rest of script

au lieu de ça?

Promise.then(result => {
   const { foo, bar } = result.data;
   // rest of script
 }, errorHandler);

Remarque: la bibliothèque Bluebird est utilisée à la place de l'implémentation native, et je ne peux pas passer de Promise à asnyc/wait ou Generators.

15
Tobias Mühl

NON, vous ne pouvez pas obtenir les données de manière synchrone d'une promesse comme vous le suggérez dans votre exemple. Les données doivent être utilisées dans une fonction de rappel. Alternativement, dans le style de programmation fonctionnelle, les données de promesse pourraient être map () ed over .

Si vous êtes d'accord en utilisant async/wait (vous devriez que ce soit génial), vous pouvez écrire du code qui semble synchrone tout en conservant l'asynchronicité d'une promesse (voir les commentaires @loganfsmyth).

const { foo, bar }  = await iAmAPromise.then(result => result.data);

Dans l'ensemble, puisque vous utilisez déjà ES6, je suppose que vous utilisez également un transpilateur. Dans ce cas, vous devez absolument essayer asynchrone/attendre un essai. Assurez-vous simplement de peser dans la décision que, comme aujourd'hui, ils ne sont pas encore une spécification ratifiée.

22
silkAdmin

Bien que vous puissiez obtenir une valeur d'une promesse attendue à l'intérieur d'une fonction asynchrone (simplement parce qu'elle suspend la fonction pour attendre un résultat), vous ne pouvez jamais obtenir une valeur directement d'une promesse et la remettre dans la même portée que la promesse elle-même .

C'est parce que "hors" signifierait essayer de prendre quelque chose qui existe dans le futur (la valeur finalement résolue) et le mettre dans un contexte (affectation de variable synchrone) qui s'est déjà produit dans le passé .

C'est-à-dire un voyage dans le temps. Et même si le voyage dans le temps était possible, ce ne serait probablement pas une bonne pratique de codage car le voyage dans le temps peut être très déroutant. :)

En général, si vous vous sentez comme vous devez le faire, c'est bon signe que vous devez refactoriser quelque chose. Notez que ce que vous faites avec "result => result.data" ici:

Promise.then(result => result.data, errorHandler);
// rest of script

..is déjà un cas où vous travaillez avec (littéralement, mappant) la valeur en la passant à une fonction. Mais, en supposant que "// reste du script" fasse quelque chose d'important lié à cette valeur, vous voudrez probablement continuer le mappage sur la valeur maintenant mise à jour avec encore une autre fonction qui fait alors quelque chose d'effet secondaire-y avec la valeur (comme afficher les données à l'écran).

Promise
    .then(result => result.data)
    .then(data => doSomethingWithData)// rest of script
    .catch(errorHandler);

"doSomethingWithData" sera appelé ( si il est déjà appelé) à un moment inconnu dans le futur. C'est pourquoi il est recommandé d'encapsuler clairement tout ce comportement dans une fonction spécifique, puis de connecter cette fonction à la chaîne Promise.

C'est honnêtement mieux de cette façon, car cela vous oblige à déclarer clairement une séquence particulière d'événements qui se produira , explicitement séparée de la première exécution à travers tous l'exécution de votre code d'application.

En d'autres termes, imaginez ce scénario, exécuté hypothétiquement dans la portée globale de niveau supérieur:

const { foo, bar } = Promise.then(result => result.data, errorHandler);
console.log(foo);
//...more program

À quoi vous attendriez-vous? Il y a deux possibilités, et les deux sont mauvaises.

  1. Votre programme entier aura pour s'arrêter et attendre que la promesse s'exécute avant de savoir ce que "foo" & "bar" voudraient ... non, pourrait être. (c'est ce que "attendre", à l'intérieur d'une fonction asynchrone, fait en fait: il suspend l'exécution de la fonction entière jusqu'à ce que la valeur soit disponible ou qu'une erreur soit levée)
  2. foo et bar seraient simplement indéfinis (c'est ce qui se passe réellement), car, exécutés de manière synchrone, ils ne seraient que des propriétés inexistantes de l'objet Promise de niveau supérieur (qui n'est pas lui-même une "valeur", mais plutôt un wrapper quasi-monadique autour obtenant une valeur éventuelle OR une erreur) qui le plus probable ne contient pas encore de valeur.
5
Dtipson