はじめに
JavaScriptを学習していると必ず出会う「非同期処理」と「Promise」。この記事では、これらの基本的な概念を図解を交えて分かりやすく解説します。
非同期処理とは
非同期処理とは、時間のかかる処理を開始したら、その完了を待たずに次の処理に進める仕組みです。
同期処理との違い
同期処理 は、処理を順番に1つずつ実行します。1つの処理が完了するまで、次の処理は待機する必要があります。
非同期処理 は、時間のかかる処理を開始したら完了を待たずに次の処理に進めます。結果が返ってきたら、その時点で続きの処理を実行します。
日常生活での例え
レストランと出前で考えると分かりやすいです。
同期処理:レストランで注文
- 注文する
- 料理ができるまでその場で待つ
- 料理を受け取る
- 次の行動ができる
非同期処理:出前を注文
- 注文する
- 配達を待つ間、他のこと(掃除、勉強など)ができる
- 配達が来たら受け取る
なぜ非同期処理が必要か
JavaScriptでは以下のような処理に時間がかかります。
- サーバーからのデータ取得
- ファイルの読み込み
- タイマー処理
- 画像の読み込み
これらを同期処理で行うと、完了するまでブラウザやアプリ全体が固まってしまいます。非同期処理を使えば、待っている間も他の処理を受け付けられます。
Promiseとは
Promiseは、非同期処理の結果を表すオブジェクトです。「将来的に値が返ってくることを約束するもの」と考えると良いでしょう。
Promiseの3つの状態
Promiseは常に以下の3つの状態のいずれかにあります。
- Pending - 処理がまだ完了していない初期状態
- Fulfilled - 処理が成功して完了した状態
- Rejected - 処理が失敗して完了した状態
Promiseが「解決する」とは
「Promiseが解決する」とは、PendingからFulfilledまたはRejectedのどちらかの状態に変わることを指します。つまり、非同期処理が完了して結果が確定することです。
サーバーにデータを取得しに行く場合で考えてみましょう。
- Pending - サーバーにリクエストを送信中。まだ応答が返ってきていない
- Fulfilled - サーバーから正常にデータが返ってきた
- Rejected - ネットワークエラーなどで失敗した
async/awaitとPromise
asyncとawaitは、Promiseをより直感的に扱うための構文です。
なぜセットで使うのか
awaitはasync関数の中でしか使えないという文法上の制約があるためです。
それぞれの役割
asyncの役割
- 関数を非同期関数として定義する
- その関数は必ずPromiseを返すようになる
- 関数内で
awaitを使えるようにする
awaitの役割
- Promiseの結果が解決されるまで、その場で処理を待機する
- Promiseが解決されたら、その結果の値を返す
- コードを同期処理のように書けるようにする
なぜこの設計なのか
awaitで処理を待機している間、JavaScriptのメインスレッドをブロックしてはいけません。そのため、awaitを使う関数自体も非同期関数である必要があります。
asyncキーワードをつけることで、その関数全体が非同期処理として扱われ、他の処理を妨げることなく待機できるようになります。
つまり、「待つ」ためには「待てる場所」が必要ということです。
まとめ
- 非同期処理は時間のかかる処理を待たずに次に進める仕組み
- Promiseは非同期処理の結果を表すオブジェクトで、Pending、Fulfilled、Rejectedの3つの状態を持つ
- Promiseが解決するとは、処理が完了して結果が確定すること
-
awaitはasync関数内でのみ使用でき、Promiseの解決を待つ - この仕組みにより、ブラウザやアプリを固まらせることなくスムーズな処理が実現できる
非同期処理の概念を理解することで、JavaScriptでのより効果的なコーディングが可能になります。