async/await: 同期風の非同期コード
Promise を同期コードのように書く。ES2017の革命。
async/await
なぜasync/awaitが必要か?
async/awaitは「Promiseを同期コードのように書ける構文」です。Promiseチェーン(`.then().then().then()`)は、コードが読みにくくなり、エラーハンドリングも複雑になります。async/awaitを使うと、同期的なコードのように書けるため、コードが読みやすく、エラーハンドリングも簡単になります。
いつ使うか?
async/awaitは、以下のような場面で使います: 1. **APIリクエスト**: 複数のAPIを順番に呼び出すとき。 2. **ファイル操作**: ファイルの読み込みや書き込みを順番に実行したいとき。 3. **データベース操作**: データベースへのクエリを順番に実行したいとき。 4. **エラーハンドリング**: try/catchブロックでエラーをキャッチしたいとき。
実践テクニック
並列実行を活用する
独立した非同期処理がある場合、`Promise.all()` を使って並列実行を活用してください。これにより、処理時間を大幅に短縮できます。例:複数のAPIを同時にリクエストして、すべてのレスポンスを待つ。ただし、順番が重要な場合は、順次実行(awaitを連続)を使ってください。
エラーハンドリング
async/awaitを使うと、try/catchブロックでエラーをキャッチできます。エラーが発生した場合、適切なエラーメッセージを表示し、ユーザーに通知することが重要です。また、`.catch()` メソッドを使って、Promiseチェーンでエラーハンドリングすることも可能です。
トップレベルawait
ES2022以降、モジュールのトップレベルでawaitを使えるようになりました。これにより、非同期処理を初期化する際、IIFE(即時実行関数式)を使う必要がなくなりました。ただし、トップレベルawaitは慎重に使ってください。モジュールの初期化がブロックされる可能性があるためです。
async/awaitとPromiseの使い分け
async/awaitは「同期的なコードのように書ける」ため、通常はasync/awaitを使います。ただし、`Promise.all()`、`Promise.race()`、`Promise.allSettled()` などのPromiseメソッドは、並列実行やエラーハンドリングに便利です。また、既存のPromiseチェーンをasync/awaitに書き換える場合、`try/catch` ブロックを使ってエラーハンドリングを行ってください。
async/awaitのデバッグ
async/awaitは非同期処理であるため、デバッグが難しい場合があります。Chrome DevToolsの「Sources」タブでブレークポイントを設定し、非同期処理の状態を確認してください。また、`console.log()` を使って、非同期処理の状態を出力することも有効です。
async/awaitのパフォーマンス
async/await自体は、Promiseと同じパフォーマンスを持ちます。ただし、不必要なawaitを使うと、処理が遅くなる可能性があります。例:`await Promise.resolve()` のような不必要なawaitは避けてください。また、並列実行を活用することで、処理時間を短縮できます。
// async/await 基礎async function fetchData() { const response = await fetch('/api/data'); const data = await response.json(); return data;}
// エラーハンドリングasync function safeFetch() { try { const data = await fetchData(); console.log(data); } catch (error) { console.error('Error:', error); }}// ❌ Bad: then チェーンfetch('/api/users') .then(res => res.json()) .then(users => fetch(`/api/posts/${users[0].id}`)) .then(res => res.json()) .then(posts => console.log(posts));// ✅ Good: async/awaitasync function getPosts() { const res = await fetch('/api/users'); const users = await res.json(); const postsRes = await fetch(`/api/posts/${users[0].id}`); return postsRes.json();}パターン
// 並列実行async function parallel() { const [users, products] = await Promise.all([ fetch('/api/users').then(r => r.json()), fetch('/api/products').then(r => r.json()) ]);}
// 順次実行async function sequential() { const user = await getUser(); const profile = await getProfile(user.id); const settings = await getSettings(user.id);}
// トップレベル await (ES2022)const config = await fetch('/config.json').then(r => r.json());合格ライン
演習課題
参考文献
この記事は以下の公的ガイドライン/標準に基づいています。
- MDN - async function - 非同期関数の宣言
- MDN - await - Promiseの完了を待つ演算子
- MDN - Promise.all() - 並列実行メソッド
- MDN - Using Promises - Promiseの使い方