web-dev-qa-db-ja.com

非同期関数が値ではなくPromise {<pending>}を返すのはなぜですか?

私のコード:

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

そして私がこのような何かを実行しようとすると:

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

私は手に入れました:

Promise { <pending> }

しかし、なぜ?

私の主な目標は、約束を返すgoogle.login(data.username, data.password)からトークンを変数に入れることです。そしてその後にのみ、いくつかのアクションを実行します。

63
Src

その結果がまだ解決されていない限り、約束は常に保留中のログを記録します。約束の状態(解決済みまたは未定)に関係なく、結果を取得するには、約束に対して.thenを呼び出す必要があります。

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"
})

何故ですか?

約束は順方向のみです。あなたはそれらを一度だけ解決することができます。 Promiseの解決された値は、その.thenまたは.catchメソッドに渡されます。

詳細

Promises/A +の仕様によると:

プロミス解決手順は、入力としてプロミスと値を取る抽象操作で、これを[[Resolve]](プロミス、x)と表します。 xが可算ならば、xは少なくともいくらか約束のように振る舞うという仮定の下で、約束にxの状態を採用させることを試みます。そうでなければ、それは値xで約束を満たす。

このテーブルの処理により、Promise/A +準拠のthenメソッドが公開されている限り、promise実装は相互運用できます。また、Promises/A +の実装では、妥当なthenメソッドを使って非準拠の実装を「同化」することもできます。

この仕様はパースするのが少し難しいので、それを分解しましょう。規則は以下のとおりです。

.thenハンドラ内の関数が値を返す場合、Promiseはその値で解決されます。ハンドラが別のPromiseを返した場合、元のPromiseは連鎖したPromiseの解決された値で解決されます。次の.thenハンドラーは常に、前の.thenで返された連鎖約束の解決された値を含みます。

それが実際にどのように機能するかは、以下でより詳細に説明されます。

1。 .then関数の戻り値は、promise.の解決された値になります。

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。 .then関数がPromiseを返す場合、その連鎖約束の解決された値は次の.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"
  });
98
Bamieh

私はこの質問が2年前に尋ねられたことを知っています、しかし私は同じ問題にぶつかりました、そして、問題に対する答えはES6以来です、あなたは単に関数戻り値のようにawaitをすることができます:

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
6
Marius Seack

thenメソッドは、保留中のpromiseを返します。これは、thenの呼び出しで登録された結果ハンドラの戻り値によって非同期に解決されるか、呼び出されたハンドラ内でエラーをスローすることによって拒否されます。

そのため、AuthUserを呼び出しても突然ユーザーを同期的にログインさせることはありませんが、ログインが成功した(または失敗した)後に登録されたハンドラーが呼び出されるという約束を返します。私は全てのログイン処理をlogin promiseのthen節で起動することを提案します。例えば。名前付き関数を使用してフローの順序を強調する

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);
}
2
traktor53

PromiseのMDNセクションを参照してください。 特に、 then()の戻り型に注目してください。

ログインするには、ユーザーエージェントはサーバーにリクエストを送信し、レスポンスを受信するのを待つ必要があります。ラウンドトリップ中にアプリケーションが完全に実行を停止すると、通常はユーザーエクスペリエンスが悪くなります。ログインする(または他の形式のサーバーとのやり取りを行う)JS機能では、Promiseなどが使用されます非同期に結果を配信するため。

さて、returnステートメントは常にそれらが現れる関数の文脈で評価されることにも注意してください。

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

ステートメントreturn token;は、then()に渡される無名関数がトークンを返すべきであることを意味しました。AuthUser関数が返すべきではないことを意味します。 AuthUserが返すのは、google.login(username, password).then(callback);を呼び出した結果です。

最終的にあなたのコールバックtoken => { return token; }は何もしません。代わりに、then()への入力は実際に何らかの方法でトークンを処理する関数である必要があります。

0
Jesse Amano