非同期処理の書き方

JavaScriptの非同期処理は、従来はPromiseやthen/catchを使用して書くのが一般的でした。しかし、async/await構文が導入されたことで、非同期処理をよりシンプルで直感的に書くことができるようになりました。
async/awaitを使うと、非同期処理を同期的なコードに近い形で記述できます。そのため、APIからデータを取得する処理や、時間のかかる処理を順番に扱う場面で、コードの流れを理解しやすくなります。
async/awaitの基本的な使い方
asyncは関数を非同期関数にするためのキーワードです。asyncを付けた関数は、必ずPromiseを返します。
その関数の中でawaitを使うと、Promiseの処理が完了するまで、その行で待機できます。ただし、ページ全体が完全に停止するわけではなく、他の処理は必要に応じて進みます。
async/awaitの基本構文
async function fetchData() {
const response = await fetch("https://api.example.com/data");
const data = await response.json();
console.log(data);
}
fetchData();
この例では、fetchメソッドでAPIからデータを取得し、その後json()でJSON形式のデータに変換しています。
fetch()でデータを取得する処理を開始します。awaitによって、レスポンスが返るまで待ちます。response.json()でレスポンスの中身をJavaScriptのオブジェクトとして扱える形に変換します。- 取得したデータを
console.log()で表示します。
async/awaitの利点
async/awaitには、次のような利点があります。
| 利点 | 説明 |
|---|---|
| 可読性の向上 | コードが上から下へ自然に読めるため、処理の流れを理解しやすくなります。 |
| エラーハンドリングが簡単 | try/catchを使って、非同期処理のエラーをまとめて処理できます。 |
| Promiseチェーンを減らせる | then()を何度もつなげる書き方を避けられ、コードが見やすくなります。 |
| 順番に処理したい場合に分かりやすい | 前の処理が終わってから次の処理を行う流れを簡単に書けます。 |
エラーハンドリングとasync/await
非同期処理では、通信エラーやデータ取得の失敗などが発生することがあります。そのため、実際のコードではtry/catchを使ってエラーに備えることが重要です。
ただし、fetch()はネットワークエラーの場合は失敗しますが、HTTPステータスコードが404や500の場合でも、それだけでは自動的にcatchへ移動しません。そのため、response.okを使ってレスポンスが正常か確認するのが実践的です。
async/awaitでのエラーハンドリングの例
async function fetchData() {
try {
const response = await fetch("https://api.example.com/data");
if (!response.ok) {
throw new Error(`HTTPエラー: ${response.status}`);
}
const data = await response.json();
console.log(data);
} catch (error) {
console.error("エラーが発生しました:", error);
}
}
fetchData();
この例では、fetch()の結果を受け取った後に、response.okで通信が成功したか確認しています。
tryブロック内に、通常の非同期処理を書きます。response.okがfalseの場合は、throwでエラーを発生させます。- エラーが発生した場合は、
catchブロックで処理します。
初心者のうちは、await fetch()だけで完全にエラー処理ができると思いがちですが、HTTPエラーの確認も忘れないようにしましょう。
複数の非同期処理を書く
async/awaitを使うことで、複数の非同期処理を順番に実行する場合でも、コードをシンプルに書けます。
ただし、順番に実行する必要がない処理までawaitで1つずつ待ってしまうと、処理全体が遅くなることがあります。順番が重要な処理なのか、並行して実行できる処理なのかを意識することが大切です。
複数の非同期処理を順番に実行する例
async function fetchAllData() {
const response1 = await fetch("https://api.example.com/data1");
const data1 = await response1.json();
console.log("データ1:", data1);
const response2 = await fetch("https://api.example.com/data2");
const data2 = await response2.json();
console.log("データ2:", data2);
}
fetchAllData();
この例では、1つ目のAPIリクエストが完了してから、2つ目のAPIリクエストを実行しています。
「1つ目の結果を使って2つ目の処理を行う」ような場合には、この書き方が適しています。
async/awaitとPromise.allの組み合わせ
async/awaitとPromise.all()を組み合わせると、複数の非同期処理を並行して実行し、すべての結果が揃うのを待つことができます。
複数のAPIリクエストに依存関係がない場合は、順番に待つよりもPromise.all()で並行実行した方が効率的です。
async/awaitとPromise.allを組み合わせた例
async function fetchAllData() {
const [response1, response2] = await Promise.all([
fetch("https://api.example.com/data1"),
fetch("https://api.example.com/data2")
]);
const [data1, data2] = await Promise.all([
response1.json(),
response2.json()
]);
console.log("データ1:", data1);
console.log("データ2:", data2);
}
fetchAllData();
この例では、2つのfetch()を同時に開始し、両方のレスポンスが返ってくるまで待っています。その後、取得したレスポンスをJSON形式に変換しています。
Promise.all()は、配列内のすべてのPromiseが成功した場合に結果を返します。一方で、1つでも失敗すると全体が失敗として扱われるため、必要に応じてtry/catchと組み合わせて使います。
Promise.allを使うときの注意点
- 処理同士に依存関係がない場合に向いています。
- 1つでも失敗すると、全体がエラーになります。
- 順番に実行する必要がある処理には向きません。
- 大量のリクエストを一度に実行すると、サーバーやブラウザに負荷がかかることがあります。
初心者がつまずきやすいポイント
awaitは基本的にasync関数の中で使用します。async関数は戻り値を直接返しているように見えても、実際にはPromiseを返します。awaitを書き忘れると、処理結果ではなくPromiseそのものが入ることがあります。fetch()ではHTTPエラーを自分で確認する必要があります。- 順番に待つ必要がない処理は、
Promise.all()を使うと効率的です。
まとめ
async/awaitを使うと、非同期処理を読みやすく書ける。asyncを付けた関数はPromiseを返す。awaitを使うと、Promiseの完了を待ってから次の処理へ進める。- エラー処理には
try/catchを使う。 fetch()ではresponse.okを確認すると安全である。- 複数の非同期処理を並行して実行する場合は
Promise.all()が便利である。