こんな悩みはありませんか
APIからデータを取得する処理を書いていて、.then().then().then()とPromiseが連なっていくコードを見て「読みにくいな」と感じたことはないでしょうか。あるいは、非同期処理の順番がうまくいかず、データが取れる前に次の処理が走ってしまってエラーになった経験がある方も多いはずです。
非同期処理はJavaScriptを使う以上避けて通れないテーマですが、async/awaitを使うと、処理の流れを上から下へ順番に読めるコードとして書けるようになります。
この記事でできるようになること
この記事を読むと、async/awaitの基本的な書き方から、実務でよくある「複数のAPIを順番に呼ぶ」「複数の処理を並行して実行する」「エラーハンドリングをきちんと書く」といったパターンまで、手を動かしながら理解できるようになります。
async/awaitは特別な仕組みではなく、Promiseを読みやすく書くための構文だと理解しておくと、学習の負担がぐっと減ります。
async/awaitの基本を押さえる
asyncキーワードで関数を非同期にする
関数の前にasyncをつけると、その関数は自動的にPromiseを返すようになります。
async function fetchUser() {
return "ユーザー情報";
}
fetchUser().then((result) => console.log(result));
asyncをつけただけの関数でも、戻り値は自動的にPromiseでラップされます。ここはまず「そういうものだ」と受け止めてもらえれば大丈夫です。
awaitで処理の完了を待つ
awaitは、Promiseの結果が返ってくるまで処理を一時停止させるキーワードです。async関数の中でしか使えない点に注意してください。
async function getUserData() {
const response = await fetch("https://api.example.com/user");
const data = await response.json();
console.log(data);
}
上から下に読むだけで処理の順番がわかるので、.then()を重ねるより格段に見通しがよくなります。
実務で使えるコード例
複数のAPIを順番に呼び出す
ユーザー情報を取得したあと、そのIDを使って注文履歴を取得する、といった処理は実務でもよくあります。
async function getOrderHistory() {
const user = await fetchUser();
const orders = await fetchOrders(user.id);
return orders;
}
複数の処理を並行して実行する
互いに依存しない処理をawaitで順番に書いてしまうと、無駄に時間がかかります。こういうときはPromise.allと組み合わせるのがおすすめです。
async function getDashboardData() {
const [user, notifications, tasks] = await Promise.all([
fetchUser(),
fetchNotifications(),
fetchTasks(),
]);
return { user, notifications, tasks };
}
個人的には、この「並行化できる処理はないか」を意識するだけで、体感速度がかなり変わると感じています。
try/catchでエラーハンドリングする
async/awaitではエラー処理をtry/catchで書けます。これは.then().catch()より直感的です。
async function safeFetchUser() {
try {
const response = await fetch("https://api.example.com/user");
if (!response.ok) {
throw new Error("通信に失敗しました");
}
return await response.json();
} catch (error) {
console.error("エラーが発生しました:", error.message);
return null;
}
}
ポイント:async関数の中でエラーが発生する可能性がある処理は、必ずtry/catchで囲んでおきましょう。囲まないと、エラーが握りつぶされたまま気づきにくくなります。
つまずきやすいポイントと対処
awaitを忘れる
最初は戸惑いやすいポイントですが、Promiseを返す処理にawaitをつけ忘れると、結果ではなくPromiseオブジェクトそのものが変数に入ってしまいます。コンソールにPromise { <pending> }と表示されたら、まずここを疑ってみてください。
forEachの中でawaitが効かない
forEachのコールバック内でawaitを書いても、順番通りに待ってくれません。ここは正直つまずく方が多い部分です。順番に処理したい場合はfor...ofを使いましょう。
for (const id of userIds) {
const user = await fetchUser(id);
console.log(user);
}
配列の各要素を並行処理したいだけなら、mapで作ったPromiseの配列をPromise.allに渡す方法もあります。用途に応じて使い分けるとよいでしょう。
エラーハンドリングを省略してしまう
動作確認中はエラーが出ないため、ついtry/catchを後回しにしてしまいがちです。しかし本番環境では通信エラーやAPIの仕様変更など、想定外のことが必ず起こります。非同期処理を書いたら、エラー処理までセットで書く習慣をつけておくと、後々のトラブルをかなり減らせます。
注意:async関数内でthrowしたエラーは、呼び出し側でtry/catchするかPromiseの.catch()で受け取らないと、未処理のエラーとして扱われてしまいます。
まとめ
async/awaitは、非同期処理を同期処理のように読みやすく書くための構文です。基本のasyncとawaitの使い方さえ押さえれば、あとはPromise.allによる並行処理とtry/catchによるエラーハンドリングを組み合わせるだけで、実務のほとんどのケースに対応できます。
まずは自分が普段書いているコールバックやPromiseのコードを、ひとつでもいいのでasync/awaitに書き換えてみてはいかがでしょうか。実際に手を動かすことで、理解の定着が早まるはずです。
AIサブスクの月額がかさんできたら
複数のAIサービスを1つの契約にまとめて、コストを抑えながら使い倒す選択肢もあります。



コメント