Comment accéder à la valeur d'une promesse?

146

Je regarde cet exemple de la documentation d'Angular pour $qmais je pense que cela s'applique probablement aux promesses en général. L'exemple ci-dessous est copié textuellement de leurs documents avec leur commentaire inclus:

promiseB = promiseA.then(function(result) {
  return result + 1;
});

// promiseB will be resolved immediately after promiseA is resolved and its value
// will be the result of promiseA incremented by 1

Je ne sais pas comment cela fonctionne. Si je peux invoquer .then()le résultat du premier .then(), les enchaîner, ce que je sais que je peux, alors promiseBest un objet promesse, de type Object. Ce n'est pas un Number. Alors qu'entendent-ils par "sa valeur sera le résultat de promiseA incrémentée de 1"?

Suis-je censé y accéder comme promiseB.valueou quelque chose comme ça? Comment le rappel de succès peut-il retourner une promesse ET retourner "résultat + 1"? Il me manque quelque chose.

nom_utilisateur_temporaire
la source
J'ai posé une question connexe: Pourquoi Promise n'a-t-il pas de fonction get ()?
Roland
1
Est-ce que cela répond à votre question? Comment renvoyer la réponse d'un appel asynchrone?
Heretic Monkey le
Cette question est de 5 ans et a une réponse acceptée ...
temporary_user_name
@temporary_user_name: il est normal que les gens votent de près à tout moment, même sur d'anciennes questions.
halfer

Réponses:

141

promiseALa thenfonction de retourne une nouvelle promesse ( promiseB) qui est immédiatement résolue après la promiseArésolution, sa valeur est la valeur de ce qui est retourné par la fonction de succès à l'intérieur promiseA.

Dans ce cas promiseAest résolu avec une valeur - resultpuis résout immédiatement promiseBavec la valeur de result + 1.

L'accès à la valeur de promiseBse fait de la même manière que nous avons accédé au résultat depromiseA .

promiseB.then(function(result) {
    // here you can use the result of promiseB
});

Edit décembre 2019 : async/ awaitest désormais standard dans JS, ce qui permet une syntaxe alternative à l'approche décrite ci-dessus. Vous pouvez maintenant écrire:

let result = await functionThatReturnsPromiseA();
result = result + 1;

Maintenant, il n'y a pas de promiseB, car nous avons déballé le résultat de promiseA using await, et vous pouvez travailler avec lui directement.

Cependant, awaitne peut être utilisé qu'à l'intérieur d'une asyncfonction. Donc, pour faire un léger zoom arrière, ce qui précède devrait être contenu comme suit:

async function doSomething() {
    let result = await functionThatReturnsPromiseA();
    return result + 1;
}
Nachshon Schwartz
la source
2
Les promesses sont théoriquement leurs propres objets. ils contiennent un résultat accessible via la fonction de réussite de la promesse.
Nachshon Schwartz
2
Donc, si vous voulez travailler avec la valeur de retour d'un rappel asynchrone d'une promesse, cela doit être fait dans un autre rappel asynchrone. Logique. J'avais cherché un moyen d'obtenir une valeur de retour primitive ultime, mais je suppose que cela défierait la raison étant donné le contexte.
temporary_user_name
2
@Aerovistae en fait, ES6 introduit des générateurs qui rendent cela possible et ES7 introduit des fonctions asynchrones - qui vous donnent toutes deux du sucre de syntaxe par rapport aux promesses qui le font ressembler à du code synchrone (en exécutant une machine à états en arrière-plan) - alors tenez bon :)
Benjamin Gruenbaum
25

Lorsqu'une promesse est résolue / rejetée, elle appellera son gestionnaire de succès / erreurs:

var promiseB = promiseA.then(function(result) {
   // do something with result
});

La thenméthode renvoie également une promesse: promiseB, qui sera résolue / rejetée en fonction de la valeur de retour du gestionnaire de succès / erreurs de promiseA .

Il y a trois valeurs possibles que les gestionnaires de succès / erreurs de promiseA peuvent renvoyer et qui affecteront le résultat de promiseB:

1. Return nothing --> PromiseB is resolved immediately, 
   and undefined is passed to the success handler of promiseB
2. Return a value --> PromiseB is resolved immediately,
   and the value is passed to the success handler of promiseB
3. Return a promise --> When resolved, promiseB will be resolved. 
   When rejected, promiseB will be rejected. The value passed to
   the promiseB's then handler will be the result of the promise

Armé de cette compréhension, vous pouvez comprendre ce qui suit:

promiseB = promiseA.then(function(result) {
  return result + 1;
});

L'appel then renvoie immédiatement promiseB. Lorsque promiseA est résolue, il transmet le résultat au gestionnaire de succès de promiseA. Comme la valeur de retour est le résultat de promiseA + 1, le gestionnaire de succès renvoie une valeur (option 2 ci-dessus), donc promiseB se résoudra immédiatement et le gestionnaire de succès de promiseB recevra le résultat de promiseA + 1.

pixelbits
la source
4

.thenLa fonction de promiseB reçoit ce qui est renvoyé par la .thenfonction de promiseA.

ici promiseA renvoie est un nombre, qui sera disponible comme numberparamètre dans la fonction de succès de promiseB. qui sera ensuite incrémenté de 1

harishr
la source
3

L'analyse du commentaire un peu différemment de votre compréhension actuelle peut aider:

// promiseB will be resolved immediately after promiseA is resolved

Cela indique que promiseBc'est une promesse mais qui sera résolue immédiatement après la promiseArésolution. Une autre façon de voir cela signifie que promiseA.then()renvoie une promesse qui est assignée promiseB.

// and its value will be the result of promiseA incremented by 1

Cela signifie que la valeur promiseArésolue est la valeur qui promiseBrecevra comme valeur successCallback:

promiseB.then(function (val) {
  // val is now promiseA's result + 1
});
Jason Cust
la source
2

La réponse pixelbits est correcte et vous devez toujours l'utiliser .then()pour accéder à la valeur d'une promesse dans le code de production.

Cependant, il existe un moyen d'accéder à la valeur de la promesse directement après sa résolution à l'aide de la liaison node.js interne non prise en charge suivante:

process.binding('util').getPromiseDetails(myPromise)[1]

AVERTISSEMENT: process.binding n'a jamais été conçu pour être utilisé en dehors du noyau de nodejs et l'équipe principale de nodejs cherche activement à le déprécier

https://github.com/nodejs/node/pull/22004 https://github.com/nodejs/node/issues/22064

Zeus Lalkaka
la source
1

Cet exemple je trouve explicite. Remarquez comment wait attend le résultat et vous manquez donc la promesse retournée.

cryA = crypto.subtle.generateKey({name:'ECDH', namedCurve:'P-384'}, true, ["deriveKey", "deriveBits"])
Promise {<pending>}
cryB = await crypto.subtle.generateKey({name:'ECDH', namedCurve:'P-384'}, true, ["deriveKey", "deriveBits"])
{publicKey: CryptoKey, privateKey: CryptoKey}
Maître James
la source
Cela doit être dans une fonction asynchrone.
Samed le
0
promiseA(pram).then(
     result => { 
     //make sure promiseA function allready success and response
     //do something here
}).catch(err => console.log(err)) => {
     // handle error with try catch
}
Tomnyson
la source
1
Bien que ce code puisse répondre à la question, fournir un contexte supplémentaire sur la manière et la raison pour laquelle il résout le problème améliorerait la valeur à long terme de la réponse.
Alexander
0

Vous pouvez facilement le faire en utilisant une méthode d'attente asynchrone en javascript.

Vous trouverez ci-dessous un exemple de récupération d'une valeur de promesse WebRTC à l'aide d'un délai d'expiration.

function await_getipv4(timeout = 1000) {
    var t1 = new Date();
    while(!window.ipv4) {
        var stop = new Date() - t1 >= timeout;
        if(stop) {
            console.error('timeout exceeded for await_getipv4.');
            return false;
        }
    }
    return window.ipv4;
}

function async_getipv4() {
    var ipv4 = null;
    var findIP = new Promise(r=>{var w=window,a=new (w.RTCPeerConnection||w.mozRTCPeerConnection||w.webkitRTCPeerConnection)({iceServers:[]}),b=()=>{};a.createDataChannel("");a.createOffer(c=>a.setLocalDescription(c,b,b),b);a.onicecandidate=c=>{try{c.candidate.candidate.match(/([0-9]{1,3}(\.[0-9]{1,3}){3}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7})/g).forEach(r)}catch(e){}}})
    findIP.then(ip => window.ipv4 = ip);
    return await_getipv4();
};

OxFEEDFACE
la source
Il est important d'exécuter cet extrait non pas ici mais dans un vrai navigateur, je pense que cela est dû au sandboxing.
OxFEEDFACE
0

Dans le Node REPL, pour obtenir une connexion à la base de données qui était la valeur d'une promesse, j'ai adopté l'approche suivante:

let connection
try {
  (async () => {
    connection = await returnsAPromiseResolvingToConnection()
  })()
} catch(err) {
  console.log(err)
}

La ligne avec awaitrenverrait normalement une promesse. Ce code peut être collé dans le Node REPL ou s'il y est enregistré, index.jsil peut être exécuté dans Bash avec

node -i -e "$(< index.js)"

qui vous laisse dans le Node REPL après avoir exécuté le script avec accès à la variable set. Pour confirmer le retour de la fonction asynchrone, vous pouvez connectionpar exemple vous connecter , puis vous êtes prêt à utiliser la variable. Bien sûr, on ne voudrait pas compter sur la résolution de la fonction asynchrone pour tout code du script en dehors de la fonction asynchrone.

dmstack
la source
0

Il y a quelques bonnes réponses ci-dessus et voici la version de la fonction ES6 Arrow

var something = async() => {
   let result = await functionThatReturnsPromiseA();
   return result + 1;
}
roopa l
la source
0

J'apprends lentement les promesses javascript, par défaut toutes les fonctions async renvoient une promesse, vous pouvez envelopper votre résultat comme:

(async () => {
//Optional "await"
  await yourAsyncFunctionOrPromise()
    .then(function (result) {
      return result +1;
    })
    .catch(function (error) {
      return error;
    })()
})

" L'expression d'attente entraîne la suspension de l'exécution de la fonction asynchrone jusqu'à ce qu'une promesse soit réglée (c'est-à-dire remplie ou rejetée) et la reprise de l'exécution de la fonction asynchrone après son exécution. Lorsqu'elle est reprise, la valeur de l'expression d'attente est celle de la promesse remplie. . Si la promesse est rejetée, l'expression d'attente renvoie la valeur rejetée . "

En savoir plus sur les attentes et les promesses dans MDN Web Docs

Sites LT
la source
-5

Peut-être que ce petit exemple de code Typescript vous aidera.

private getAccount(id: Id) : Account {
    let account = Account.empty();
    this.repository.get(id)
        .then(res => account = res)
        .catch(e => Notices.results(e));
    return account;
}

Ici, les repository.get(id)retours a Promise<Account>. Je l'affecte à la variable accountdans l' theninstruction.

aahoogendoorn
la source
1
Votre code renvoie un compte avant que la promisse ne puisse être résolue et c'est pourquoi il a été voté à la baisse, votre code retourne toujours Account.empty ();
Felype