0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【JavaScript】async/awaitとPromiseの違い

Last updated at Posted at 2021-07-06

この記事について

コメントにて、より良い構文をいただきました。記事の最後に記載いたします。また、より高度な普通の構文で書かれたasync/awaitもコメントにて記載いただきましたので、記事の最後に記載いたしました。どのような出力順になるか考えるのが楽しく大変勉強になりました。ありがとうございました。

追記:コメントにてthenとasync/awaitを一緒に利用することはないとご指摘・解説いただきました。大変分かりやすく、非同期処理の不明点が払拭されました。ありがとうございます。
以下にコメントにて記載いただいた「Promiseとasync/await」の違いを載せました。

await と .then を一緒に使うことはしないと思います。

async関数
・自動的に Promise が作られて、関数の復帰値は Promise になる
・関数内で return したら、return値を引数にして Promise の resolve が自動的に呼び出される
・関数内で例外が発生したら、Promise の reject が自動的に呼び出される
await
・Promise の resolve か reject が呼ばれるまで待ち状態になる
・Promise の resolve が呼ばれたら、resolveの引数が await の 戻り値 になって処理が再開する
・Promise の reject が呼ばれたら、例外が発生する

async/awaitとPromiseの違い(誤っている構文)

※追記:以下の【async/awaitとPromiseの違い】は誤った構文の記載になりますが、「誤っている構文の例」として残しておきます。

Async/awaitはAsync関数内であれば、同期・非同期処理を一緒に記述して、手続き型の処理を実現できます。Promiseは、同期・非同期処理を一緒に記述した場合、thenでつないだり処理の前後を完璧に把握する必要があります。
以下はPromiseを使った、同期・非同期処理を一緒に記述した場合です。

function test() {
  console.log("関数開始");
  takeLongTimeFn().then((a) => console.log(a));
  function takeLongTimeFn() {
    return new Promise((resolve, reject) => {
      setTimeout(function () {
        resolve("成功");
      }, 2000);
    });
  }
  console.log("関数終了");
}

test();

/*
関数開始
関数終了
成功
*/

最後のコメントアウトした部分が実際の出力結果です。このようにPromiseを用いると手続き型ではなくなり非同期で処理が走ります。それを解決するために以下のように記載の順序を書き換えます。

function test() {
  console.log("関数開始");
  takeLongTimeFn().then((a) => {
    console.log(a);
    console.log("関数終了");
  });
  function takeLongTimeFn() {
    return new Promise((resolve, reject) => {
      setTimeout(function () {
        resolve("成功");
      }, 2000);
    });
  }
}

test();
/*
関数開始
成功
関数終了
*/

このように記載すれば関数開始→成功→関数終了の順でログが出力されます。しかし見ての通り出力の順番が手続き型となっていないため、読みづらいです。そこでasync/awaitを利用します。同じ処理をasync/awaitで記載したものが以下になります。

async function test() {
  console.log("関数開始");
  await takeLongTimeFn().then((a) => {
    console.log(a);
  });
  function takeLongTimeFn() {
    return new Promise((resolve, reject) => {
      setTimeout(function () {
        resolve("成功");
      }, 2000);
    });
  }
  console.log("関数終了");
}

test();
/*
関数開始
成功
関数終了
*/

このように、同期・非同期処理を一緒に記述している関数の前に、asyncを付けることでその関数内で実行される非同期関数にawaitを付けることができます。awaitが付けられた関数が実行されるとその関数はPromiseが返ってくるまで次の処理に進むことがありません。

同様の処理で可読性の高い構文(コメント参照)

async function test() {
  console.log("関数開始");
  let message = await takeLongTimeFn()
  console.log(message);
  console.log("関数終了");
}

function takeLongTimeFn() {
  return new Promise(resolve => setTimeout(() => resolve("成功"), 2000));
}

test();
/*
関数開始
成功
関数終了
*/

普通のasync/await構文

async function takeLongTimeFn(type) {
  await new Promise(resolve => setTimeout(resolve, 2000));
  return type + "成功";
}

function synctest() {
  console.log("sync関数開始");
  takeLongTimeFn("sync").then(message => {
    console.log(message);
    console.log("sync関数then終了");
  });
  console.log("sync関数終了");
}

async function asynctest() {
  console.log("async関数開始");
  let message = await takeLongTimeFn("async")
  console.log(message);
  console.log("async関数終了");
}

synctest();
asynctest();
/*
sync関数開始
sync関数終了
async関数開始
sync成功
sync関数then終了
async成功
async関数終了
*/
0
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?