Web開発の現場において、非同期処理は避けて通れない重要なテーマです。APIからのデータ取得やファイルの読み込みなど、時間のかかる処理を扱う際に「処理が終わるのを待たずに次のコードが実行されてしまう」という課題に直面したことはありませんか?
従来のコールバック関数による実装では、処理が重なるごとにコードが右側に深く入り込んでいく「コールバック地獄」に陥りやすく、保守性が著しく低下します。本記事では、この課題を解決し、モダンで読みやすい非同期処理を実現するための「Promise」と「async/await」の活用術を解説します。
基礎知識:Promiseとは何か
Promiseは、非同期処理の「完了」または「失敗」を表現するオブジェクトです。Promiseは以下の3つの状態を持ちます。
・pending(待機中):処理がまだ完了していない初期状態。
・fulfilled(完了):処理が成功し、結果が返された状態。
・rejected(拒否):処理が失敗し、エラーが発生した状態。
この状態の変化に応じて、成功時には.then()、失敗時には.catch()メソッドで後続の処理を指定できるのが特徴です。
実装:Promiseチェーンとエラーハンドリング
非同期処理が連続する場合、Promiseを連結させる「Promiseチェーン」を利用します。これにより、ネストを深くすることなく、直列的な処理を記述できます。
以下は、fetch APIを使用してデータを取得し、エラーハンドリングまで含めた実用的なコード例です。
サンプルプログラム
// 非同期でデータを取得する関数
function fetchUserData(url) {
return fetch(url)
.then(response => {
// HTTPレスポンスが正常か確認
if (!response.ok) {
throw new Error(‘ネットワークレスポンスが正常ではありません’);
}
return response.json(); // JSONデータを解析して次のthenへ渡す
})
.catch(error => {
// 途中で発生した全てのエラーをここで一括処理
console.error(‘取得エラー:’, error);
});
}
// 実行例
fetchUserData(‘https://jsonplaceholder.typicode.com/users/1’)
.then(data => {
if (data) console.log(‘取得データ:’, data);
});
応用:async/awaitによる同期的な記述
ES2017で導入されたasync/await構文を使うと、Promiseをより直感的に、まるで同期処理のように記述できます。
asyncを付けた関数内でawaitを使うと、Promiseが解決されるまで関数の実行を一時停止させ、結果を取得できます。これにより、複雑なチェーン構造をフラットに保つことが可能です。
注意点と現場でのテクニック
1. 並列処理の最適化:
全ての処理をawaitで待機させると、処理が逐次実行となりパフォーマンスが低下します。依存関係のない複数のAPIリクエストを投げる場合は、Promise.all()を活用しましょう。これにより、全ての非同期処理を並列で実行し、全て完了した時点で結果を得ることができます。
2. エラーハンドリングの徹底:
async/awaitを使用する場合は、従来の.catch()の代わりにtry…catch構文でエラーをキャッチします。現場では、予期せぬ通信エラーやパースエラーを確実に捕まえられるよう、tryブロックの範囲には注意を払いましょう。
3. ブラウザ互換性:
現代のブラウザであればほぼ標準でサポートされていますが、IE11などのレガシー環境を考慮する必要がある場合は、Polyfillの導入やトランスパイル設定(Babel等)が必須となります。
非同期処理を正しく理解し、async/awaitを使いこなすことで、コードの可読性と堅牢性は劇的に向上します。ぜひ、日々の開発に取り入れてみてください。

コメント