🐕

JavaScriptのasync/awaitについて確認する

2023/12/03に公開

1.記事の目的

前回JSのPromiseについて記事を書きました。
https://zenn.dev/tomokumo/articles/2bcb70531db6da

Promiseの概念を利用してより簡潔に非同期処理を同期的に処理することができる、async/awaitについて確認していきます。

2.async/await

まず、前回のコードをasync/awaitを利用した形に書き換えます

Promise
function addNumbers(a, b) {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      if (typeof a !== 'number' || typeof b !== 'number') {
        reject(new Error("引数は数値である必要があります。"));
	// if文の条件が満たされるとreject関数が実行される
      } else {
        const result = a + b;
        console.log(`The sum of ${a} and ${b} is ${result}.`);
        resolve(result);
	//それ以外の場合にresolve関数が実行
      }
    }, 1000);
  });
}

function displayResult(result) {
  console.log(`The final result is ${result}.`);
}

function displayError(error) {
  console.log(`An error occurred: ${error.message}`);
}

addNumbers(3, 7)
  .then(displayResult) 
  .catch(displayError); 
async/await
function addNumbers(a, b) {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      if (typeof a !== 'number' || typeof b !== 'number') {
        reject(new Error("引数は数値である必要があります。"));
      } else {
        const result = a + b;
        console.log(`The sum of ${a} and ${b} is ${result}.`);
        resolve(result);
      }
    }, 1000);
  });
}

function displayResult(result) {
  console.log(`The final result is ${result}.`);
}

function displayError(error) {
  console.log(`An error occurred: ${error.message}`);
}

async function calculateAndDisplay(a, b) {
  try {
    const result = await addNumbers(a, b);
    displayResult(result);
  } catch (error) {
    displayError(error);
  }
}

calculateAndDisplay(3, 7);

1.async

async/awaitを利用している部分を詳しくみていこうと思います。
下記の例を見てみましょう。

async function asyncFunc1() {
  return 1;
}

これを実行するときちんとPromiseオブジェクトが返ってきます。
functionの前にasyncをつけることで、Promiseを返してもらうことができるようになります。
つまり、Promiseの挙動を利用して非同期処理を扱う関数を作成できるようになります。
async/awaitを利用する際にPromiseを理解しておくと何が起きているのかよくわかるようになると思います。

2.await

awaitasyncの中でのみ使うことができます。
awaitをつけた式は返されたPromiseがfulfilled状態になるかかreject状態になるまで実行を中断することで、Promiseを返す関数を同期しているかのように動作させます。
fetch()の例を見てみたと思います。

async function example() {
  const response = await fetch("http://example.com/examples.json");
  const example = await response.json();
  console.log(example);
}

まずconst response = await fetch("http://example.com/examples.json");とawaitをつけることで、fetch()がPromiseを返すまでこれ以降の処理がされません。さらにconst example = await response.json();とこちらにもawaitをつけることで、console.logも前の処理が終わるまで処理されません。これにより、

fetch()する → response.json()する →console.log()する

という順番が守られます。

最初の例のasync/await文で何が起きているのかコメントを記入したいと思います。

async function calculateAndDisplay(a, b) { 
// asyncを付けてPromiseとawaitを扱えるようにする
  try {
    const result = await addNumbers(a, b); 
    // setTimeoutを含むaddNumbers()の処理が終わるまで次の処理に進まない
    displayResult(result);
  } catch (error) {
    displayError(error);
  }
}

.thenと.catchではなく、普通のtry-catch文でエラーの出しわけを行うようにしています。

3.記事のまとめ

非同期処理を同期的に処理したい場面にはよく遭遇しますが、何だかよくわからないけどasync/awaitで実現できてしまっていました。
今回記事として同期/非同期処理〜Promise〜async/awaitとまとめることで、理解が進んだと思います。
技術的に明らかな誤りに気がついた方がいましたら、コメントで教えていただければありがたいです。

4.参考記事

https://qiita.com/soarflat/items/1a9613e023200bbebcb3
https://ja.javascript.info/async-await
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/async_function

Discussion