web-dev-qa-db-fra.com

Pourquoi ma fonction asynchrone renvoie-t-elle Promise {<en attente>} au lieu d'une valeur?

Mon code:

let AuthUser = data => {
  return google.login(data.username, data.password).then(token => { return token } )
}

Et quand j'essaye de faire quelque chose comme ça:

let userToken = AuthUser(data)
console.log(userToken)

Je suis en train:

Promise { <pending> }

Mais pourquoi?

Mon objectif principal est d'obtenir le jeton de google.login(data.username, data.password) qui renvoie une promesse, dans une variable. Et alors seulement, préformez certaines actions.

73
Src

La promesse se connectera toujours en attente tant que ses résultats ne sont pas encore résolus. Quel que soit l'état de la promesse (résolu ou toujours en attente), vous devez appeler .then sur la promesse pour capturer les résultats:

let AuthUser = function(data) {
  return google.login(data.username, data.password).then(token => { return token } )
}

let userToken = AuthUser(data)
console.log(userToken) // Promise { <pending> }

userToken.then(function(result) {
   console.log(result) // "Some User token"
})

Pourquoi donc?

Les promesses ne sont que de l'avant; Vous ne pouvez les résoudre qu'une seule fois. La valeur résolue d'un Promise est transmise à ses méthodes .then ou .catch.

Détails

Selon les spécifications Promises/A +:

La procédure de résolution de promesse est une opération abstraite prenant en entrée une promesse et une valeur, que nous désignons par [[Résoudre]] (promesse, x). Si x est une instance vérifiable, il tente de faire en sorte que la promesse adopte l'état de x, en supposant que x se comporte au moins un peu comme une promesse. Sinon, il remplit la promesse avec la valeur x.

Ce traitement de thenables permet l’interopérabilité des implémentations de promesse, à condition qu’elles exposent ensuite une méthode conforme à Promises/A +. Cela permet également aux implémentations de Promises/A + d'assimiler des implémentations non conformes avec des méthodes raisonnables.

Cette spécification est un peu difficile à analyser, alors décomposons-la. La règle est la suivante:

Si la fonction dans le gestionnaire .then renvoie une valeur, la valeur Promise est résolue avec cette valeur. Si le gestionnaire retourne un autre Promise, l'original Promise est résolu avec la valeur résolue de la chaîne Promise. Le prochain gestionnaire .then contiendra toujours la valeur résolue de la promesse chaînée renvoyée dans le précédent .then.

Son fonctionnement est décrit ci-dessous plus en détail:

1. Le retour de la fonction .then sera la valeur résolue de la promesse.

function initPromise() {
  return new Promise(function(res, rej) {
    res("initResolve");
  })
}

initPromise()
  .then(function(result) {
    console.log(result); // "initResolve"
    return "normalReturn";
  })
  .then(function(result) {
    console.log(result); // "normalReturn"
  });

2. Si la fonction .then renvoie un Promise, alors la valeur résolue de cette promesse chaînée est transmise au .then.

function initPromise() {
  return new Promise(function(res, rej) {
    res("initResolve");
  })
}

initPromise()
  .then(function(result) {
    console.log(result); // "initResolve"
    return new Promise(function(resolve, reject) {
       setTimeout(function() {
          resolve("secondPromise");
       }, 1000)
    })
  })
  .then(function(result) {
    console.log(result); // "secondPromise"
  });
110
Bamieh

Je sais que cette question a été posée il y a 2 ans, mais je rencontre le même problème et la réponse à ce problème est, depuis ES6, que vous pouvez simplement await les fonctions renvoient une valeur, comme:

let AuthUser = function(data) {
  return google.login(data.username, data.password).then(token => { return token } )
}

let userToken = await AuthUser(data)
console.log(userToken) // your data
8
Marius Seack

La méthode then renvoie une promesse en attente qui peut être résolue de manière asynchrone par la valeur de retour d'un gestionnaire de résultat enregistré dans l'appel à then ou rejetée en générant une erreur à l'intérieur du gestionnaire appelé.

Donc, appeler AuthUser ne connectera pas soudainement l'utilisateur de manière synchrone, mais renverra une promesse dont les gestionnaires enregistrés seront appelés une fois que la connexion sera réussie (ou échouera). Je suggère de déclencher tout le traitement de la connexion par une clause then de la promesse de connexion. PAR EXEMPLE. en utilisant des fonctions nommées pour mettre en évidence la séquence de flux:

let AuthUser = data => {   // just the login promise
  return google.login(data.username, data.password);
};

AuthUser(data).then( processLogin).catch(loginFail);

function processLogin( token) {
      // do logged in stuff:
      // enable, initiate, or do things after login
}
function loginFail( err) {
      console.log("login failed: " + err);
}
3
traktor53

Voir la section MDN sur Promises. En particulier, regardez le type de retour de then ().

Pour se connecter, l'agent utilisateur doit soumettre une demande au serveur et attendre de recevoir une réponse. Comme arrêter totalement l'exécution de votre application lors d'un aller-retour de requête crée généralement une mauvaise expérience utilisateur, pratiquement chaque fonction JS qui vous enregistre (ou exécute toute autre forme d'interaction serveur) utilise une promesse, ou quelque chose qui lui ressemble , pour fournir des résultats de manière asynchrone.

Notez également que les instructions return sont toujours évaluées dans le contexte de la fonction dans laquelle elles apparaissent. Ainsi, lorsque vous avez écrit:

let AuthUser = data => {
  return google
    .login(data.username, data.password)
    .then( token => {
      return token;
    });
};

l'instruction return token; signifiait que la fonction anonyme transmise à then() devrait renvoyer le jeton, mais pas que la fonction AuthUser devait l'être. Ce que AuthUser renvoie est le résultat de l'appel de google.login(username, password).then(callback);, qui se trouve être une promesse.

En fin de compte, votre rappel token => { return token; } ne fait rien; au lieu de cela, votre entrée dans then() doit être une fonction qui gère le jeton d'une manière ou d'une autre.

1
Jesse Amano