kemkemG0
@kemkemG0 (kenshin)

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

async,awaitの戻り値について教えて下さい!

javascript初心者です。
async,await 内で受け取った戻り値を、その外側で利用する方法がわかりません。
具体的に言うと、

async function f() {
//中略
  var data = await hoge(); // promise が解決するまで待ちます (*)
  data=data.json();
}

let gotJson=data;//asyncの外で使いたい

このようにしたいのですが、頑張ってやろうとしても戻り値がPromieオブジェクト?とやらになってしまい、その中にあるjson等を使うことができません、どうすればよいでしょうか。
async,await等の解説では括弧の内側でconsole.log()して終わっているので調べてもよくわかりませんでした。

0

1Answer

まず前提として、async関数の戻す値は遅延しているので、関数から返ってくるタイミングと同じタイミングで受け取ることはできないということがあります。

例ですが、たとえばawait sleep(1000);すると1秒待つsleep関数があるとします。

async function f() {
  await sleep(1000);
  return "hello";
}
const data = f();
// このタイミング

このdataを、すぐに(f()を呼んだのと同じタイミングで)使うことはできません。なぜなら、await sleep(1000);しているために、値が決まるのは1秒後になるからです。

このような、「値は後で決まるが、値の箱は返しておきたい」という目的のためにあるのがPromiseオブジェクトです。

Promiseオブジェクトから値を取り出す方法は主に2つあります。

  • then()メソッド
  • async関数の中でawaitする・・・これはthen()メソッドとやっていることは同じです

then()メソッドの使い方ですが、以下のようです。

data.then(result => {
  console.log(result); //=> hello
});

単純ですね。重要な事実として、thenに渡したコールバックの中のコードはいつ実行されるかわからない(基本的に、遅れる)し、処理が失敗すれば実行されないということがあります。

async関数の中でawaitする方法は以下のようになります。

async g() {
  const result = await data;
}
g();

蛇足
sleep()関数は以下のようにすると作ることができます。

const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));

以下のコードで、1秒後にhelloと表示されます。

async function f() {
  await sleep(1000);
  return "hello";
}

f().then(result => console.log(result));

追記

普通のJavaScriptのコードは、エラーを吐くことがあります。
それと同じように、Promiseの処理は失敗することがあるという意味です。

実は、awaitというのはPromiseから値を取り出す操作です。Promiseが失敗していれば、awaitは失敗して、エラーを吐きます。
エラーを吐けば、もしtry-catchで囲んでいなければ処理は強制終了になります。

async function f() {
  var data = await hoge();
  let newData = data.json();
}

この例では、hoge()の結果が失敗していれば、dataに代入される前にawaitが失敗してエラーを吐き、その後の処理は実行されません。

もし、hoge()が失敗する可能性があり、失敗した場合も何かをしたいなら、以下のような書き方ができます。

async function f() {
  try {
    var data = await hoge();
    let newData = data.json();
  } catch (reason) {
    // 失敗した場合
  }
}

また、

いつ実行されるかわからない

というのは、基本的には非同期処理が完了して値が決まったタイミングで実行されるが、タイマー処理でもなければそのタイミングがいつか予測するのは難しいという意味です(HTTPで取得する処理など)

5Like

Comments

  1. @kemkemG0

    Questioner

    回答ありがとうございます!

    >>値は後で決まるが、値の箱は返しておきたい
    const data=f() での '='が先に評価されるからどうしてもdataに代入するものが必要→とりあえず戻り値の型をPromise としておく というイメージで納得できました! (これがあってるかわかりませんが)
    >>thenに渡したコールバックの中のコードはいつ実行されるかわからない
    これは、たとえ
    async function f() {
    var data = await hoge();
    let newData=data.json();
    }
    と書いたとしてもnewDataにちゃんと値が入ってる保証がなく、let newData=await data.json();
    とかかなければいけない、ということでしょうか。

Your answer might help someone💌