はじめに
この記事は、プログラミング初心者が非同期処理について考える以下の記事の続きです。
先にこちらをご覧ください。
ここまで長かった…
毎日非同期処理について考えていました。これで最後です!!
asyncの復習
昨日の復習です。
- asyncキーワードを使って関数を定義することで、その関数は非同期処理を含むことをコードを読む人に示すことができる。
- asyncで囲んだ関数の返り値は必ずPromiseインスタンスになる
- asyncで囲んだ関数の中でawaitが使える
await
asyncを使用することで、その関数内で await を使って非同期処理を行うことができます。awaitをつけると、右側(右辺)の非同期処理が完了するまで次の処理は実行されません。
具体例で確認します。
async function fetchData() {
// 何かしらの非同期処理を行う
const response = await fetch('https://api.example.com/data');
const data = await response.json();
// 非同期処理の結果を使った後続の処理
console.log(data);
}
// 非同期関数の呼び出し
fetchData();
fetchは引数に渡したパスに対してHTTPリクエストを送信する非同期関数です。通常であれば、リクエストを送ってレスポンスが返ってくるのを待たずに、次の行が実行されます。
fetchの前にawaitをつけると、fetchの処理が完了するまで待ち、最後まで完了したら次の行を実行させることができます。上から下へ順番に実行されるのでソースコードが読みやすくなります。
この待つという概念について詳しく説明します。
awaitはPromiseインスタンスの状態が、Pending(保留中)からFulfilled(成功)またはRejected(失敗)に変わるまで、その場で非同期処理の完了を待ちます。
次の章でPromiseインスタンスの状態について解説します。
Promiseの状態
Promiseインスタンスは、pending、fulfilled、rejectedという3つの状態を持ちます。
- pending:処理が終わるのを待っている状態(初期状態)
- fulfilled:処理が成功した状態
- rejected:処理が失敗してしまった状態
const response = await fetch('https://api.example.com/data');
これを例に考えると、fetch('https://api.example.com/data')
が実行されるとき、実行時点ではPromiseインスタンスの状態はpending
ですが、resolve()
が実行されれば状態はfulfilled
に、reject()
が実行されれば状態はrejected
に変わります。
おそらくfetch関数の内部的に、HTTP通信のエラーコードによってresolve()を実行するか、reject()を実行するかの分岐が行われているのだと思われます。
イメージを考えてみました。ネットショッピングで例えてみます。
- 注文した時、状態はpendingです。
- 出荷・配送などの準備している時間が非同期処理です。
- 全ての準備が問題なく完了し、商品が届けば成功です。状態はfulfilledに変化します。
- =>成功した場合はおでかけします。
- 準備中にどこかで問題が発生し、壊れた商品が届いてしまったので失敗です。状態はrejectedに変化します。
- =>失敗した場合はクレームを入れます。
- 全ての準備が問題なく完了し、商品が届けば成功です。状態はfulfilledに変化します。
awaitはPromiseの状態が変化するまで、一時停止して非同期処理の完了を待ちます。
awaitの右辺のPromiseの状態がfulfilledとなった場合は、resolve()の引数がawaitの返り値となります。
一方、awaitの右辺のPromiseの状態がrejectedとなった場合は、その場でエラーをthrowします。エラーが発生したことを非同期処理の外に教えてくれるということです。エラーを感知できるなら、例外(エラー)が起こる可能性があるときに使って、エラーが起きた時にどうするかを書けるtry...catch構文
が使えます。
エラーハンドリング
try...catch構文を使った例外処理(エラーハンドリング)はかなりスッキリ書くことができます。
someAsyncOperation()
が失敗した場合、エラーが起きたことが伝わり、catchブロックに書いたエラー処理が実行されます。
async function myAsyncFunction() {
try {
const result = await someAsyncOperation();
// resultを使った処理
} catch (error) {
// エラー処理
}
}
async/awaitのまとめ
- awaitをつけると右側の非同期処理が完了するまで次の処理は実行されない
- =>上から下へ順番に実行されるからソースコードが読みやすい!
- awaitしたいときは、その関数をasyncで囲う
- =>そういう決まりだから覚える
- asyncで囲んだ関数の返り値は必ずPromiseインスタンスになる
- =>then/catchメソッドが使える
- awaitした非同期処理が失敗したらエラーを外に伝える
- =>そのエラーをtry/catchで捉えられる
終わりに
非同期処理、Promise、async/awaitと順を追ってまとめてきましたが、あまりにも難しすぎる。
全く理解できている気がしない…
実務で使う時に、調べた内容を思い出して実際に何が行われているのか?を意識しようと思います。