Javascript

async/await と Promise の基礎と実務エラーハンドリング完全ガイド

ⓘ本ページはプロモーションが含まれています

もっとスキルを活かしたいエンジニアへ

スポンサードリンク
働き方から選べる

無料で使えて良質な案件の情報収集ができるサービス

エンジニアの世界では、「いつでも動ける状態を作っておけ」とよく言われます。
技術やポートフォリオがあっても、自分に合う案件情報を日常的に見れていないと、いざ動こうと思った時に比較や判断が難しくなってしまいます。
普段から案件情報が集まる環境を作っておくと、良い案件が出た時にすぐ動きやすくなりますよ。
筆者自身も、メガベンチャー勤務時代に年収1,500万円を超えた経験があります。振り返ると、技術だけでなく「どんな案件や働き方があるか」を日頃から見ていたことが、キャリアの選択肢を広げるきっかけになりました。
このブログを読んでくれた方に感謝を込めて、実際に使っている情報収集サービスを紹介します。

フルリモート・週3日・高単価、どんな条件も妥協したくないなら

フリーランスボードに無料会員登録する

利用者10万人以上。業界最大規模45万件の案件。AIマッチ機能や無料の相場情報が人気。

年収800万円以上のキャリアアップ・ハイクラス正社員を視野に入れているなら

Beyond Careerに無料相談する

内定獲得率90%以上。紹介先企業とは役員クラスのコネクションがある安心と信頼できるエージェント。


スポンサードリンク

async/await の基本と Promise、try/catch 基礎

この章では async 関数 の書き方、Promise との関係性、そして例外を捕捉するための try / catch パターンを解説します。非同期処理を「同期的に」見せることでコードの可読性が向上し、エラーハンドリングも一貫した形で記述できるようになります。

async 関数の構文

async キーワードは関数宣言・式・クラスメソッドのいずれにも付与できます。
async が付いた関数は必ず Promise を返し、内部で await が出現した瞬間にその Promise の完了(解決または拒否)を待ちます。

参考: MDN の async 関数の仕様

Promise との関係

await expr は内部で Promise.resolve(expr) を呼び出し、thenable が解決されるまで処理を中断します。したがって、以下のように書くと同等になりますが、冗長にならない程度に留めておきます。

この等価性を理解しておくと、既存の Promise ベースライブラリでも await を自然に組み込めます。

try/catch による例外捕捉

await が失敗すると例外がスローされるため、通常の同期コードと同様に try / catch でハンドリングできます。エラー情報をログに残すだけでなく、必要なら再スローや代替処理へ流すことも可能です。

参考: Node.js の公式ドキュメント – Promise と async/await


トップレベル await と未捕捉例外ハンドリング(Node.js v20 LTS 対応)

Node.js 14 系からトップレベル await がサポートされ、v20 LTS では ESモジュールのデフォルト挙動として安定化しました。モジュール読み込み時に例外が発生するとプロセス全体が停止するリスクがあるため、未処理例外を安全に捕捉し、必要なら外部モニタリングへ送信する手順を示します。

基本的な使用例

トップレベル await はモジュールの評価段階で即座に実行されます。設定ファイルやデータベース接続など、起動時に必須となる非同期処理に適しています。

参考: Node.js Docs – Top‑level await

未処理例外の安全なハンドリングと Sentry 初期化例

import('./init.mjs') が失敗した場合は Promise.reject になるため、process.on('unhandledRejection') と併せて Sentry 等のエラートラッキングサービスを初期化しておくと、本番環境での可視性が大幅に向上します。

この構成により、トップレベル await が原因でサーバがクラッシュするリスクを低減しつつ、例外情報を即座に監視基盤へ送信できます。


fetch のタイムアウトと AbortController(実務向け実装)

fetch はデフォルトではネットワークエラーやサーバ停止時に無限待ちになる可能性があります。AbortControllersetTimeout を組み合わせたラッパーを用意すれば、タイムアウト処理とキャンセルロジックを一元管理できます。

timeout ラッパー関数

以下の実装は ESM 向けに書かれており、タイムアウト時には独自の TimeoutError をスローします。エラーハンドリング側で型判定ができるため、ロジックをシンプルに保てます。

AbortController のベストプラクティス

  • クリーンアップは必ず finally: タイムアウト以外でも途中でキャンセルされた場合にリソースが残らないようにする。
  • 複数リクエストの一括中止: 同じコントローラを共有すれば、たとえばユーザー操作で全タスクを停止できる。

参考: MDN – AbortController


並列処理のエラーパターン:Promise.all と Promise.allSettled

複数の非同期リクエストを同時に実行する際は、全体成功が必須か、一部成功でも続行できるか に応じて Promise.all もしくは Promise.allSettled を選択します。

全体失敗を前提にした Promise.all

すべてのタスクが成功しなければ次の処理へ進めないケース(例: トランザクション的バッチ処理)で使用します。最初に reject が起きた時点で全体が即座に失敗するため、リソース解放やロールバック処理を早期に行えます。

部分成功を許容する Promise.allSettled

全タスクの完了状態を把握したうえで、成功分だけ次工程へ進める 必要があるケース(例: 複数画像アップロード)に適しています。

参考: Node.js Docs – Promise.allSettled()


カスタム Error、構造化ロギング・モニタリング(Winston + Sentry)

エラー情報を 構造化 して出力すれば、検索性や外部モニタリングツールへの連携が格段に楽になります。以下ではカスタム Error クラスの設計指針と、実際に Winston と Sentry を組み合わせたロギング例を示します。

カスタム Error クラス設計

  • name は固定で判別しやすくする
  • ビジネスロジック固有の code と自由に拡張できる meta フィールドを持つ
  • スタックトレースは Error.captureStackTrace で正確に取得

ログと外部モニタリングの実装例

  • Winston:JSON フォーマットでコンソール/ファイル双方に出力。
  • Sentry:本番環境だけ有効化し、スタックトレースや meta を自動添付。

参考: Winston ドキュメント – https://github.com/winstonjs/winston#readme
参考: Sentry Node SDK – https://docs.sentry.io/platforms/node/


ESM と CommonJS の相互運用、テスト戦略(Jest)

プロジェクトがレガシーコードとモダンコードを混在させるケースでは、同一ロジックを両形式でエクスポートできるように設計すると移行コストが下がります。また、非同期エラーハンドリングは Jest のフェイクタイマーで確実にテストできます。

両形式でのエクスポート例

Jest を使った非同期エラーハンドリングテスト

  • jest.useFakeTimers() により setTimeout の挙動を制御し、タイムアウトロジックが期待どおりに動くか検証。
  • 成功・失敗・タイムアウトの 3 パターン を網羅すればカバレッジ要件は満たせます。

参考: Jest ドキュメント – https://jestjs.io/docs/timer-mocks


まとめ

  • async/await と try/catch は Promise をシンプルにラップし、例外処理を同期コードと同様の形で書ける点が最大の利点です。
  • トップレベル await は便利ですが、Node.js v20 LTS では process.on('unhandledRejection')uncaughtException' と併せて Sentry 等のモニタリングを組み込むことが実務上必須です。
  • fetch のタイムアウトAbortControllersetTimeout を組み合わせ、独自の TimeoutError で一元管理すると保守性が高まります。
  • 並列処理 では失敗時の要件に応じて Promise.all(全体失敗)か Promise.allSettled(部分成功)を選択してください。
  • カスタム Error クラス構造化ロギング (Winston + Sentry) により、障害情報が検索しやすくなり、迅速な復旧が可能です。
  • ESM / CommonJS 両対応Jest テスト を整備すれば、レガシーコードとの共存と品質保証の両立が実現します。

これらのベストプラクティスをプロジェクトに導入することで、非同期処理全般の信頼性・可観測性が大幅に向上し、運用コストの削減につながります。


参考リンク

項目 URL
async 関数(MDN) https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/async_function
Promise と async/await(Node.js Docs) https://nodejs.org/api/util.html#utilpromisifyoriginal
Top‑level await(Node.js v20 LTS) https://nodejs.org/api/esm.html#top-level-await
AbortController(MDN) https://developer.mozilla.org/ja/docs/Web/API/AbortController
Promise.allSettled(Node.js Docs) https://nodejs.org/api/promise.html#promiseallsettlediterable
Winston ロガー https://github.com/winstonjs/winston#readme
Sentry Node SDK https://docs.sentry.io/platforms/node/
Jest タイマーモック https://jestjs.io/docs/timer-mocks

これらの公式資料を併せて読むことで、この記事で扱ったテクニックの背後にある仕様やベストプラクティスをさらに深く理解できます。

スポンサードリンク

もっとスキルを活かしたいエンジニアへ

スポンサードリンク
働き方から選べる

無料で使えて良質な案件の情報収集ができるサービス

エンジニアの世界では、「いつでも動ける状態を作っておけ」とよく言われます。
技術やポートフォリオがあっても、自分に合う案件情報を日常的に見れていないと、いざ動こうと思った時に比較や判断が難しくなってしまいます。
普段から案件情報が集まる環境を作っておくと、良い案件が出た時にすぐ動きやすくなりますよ。
筆者自身も、メガベンチャー勤務時代に年収1,500万円を超えた経験があります。振り返ると、技術だけでなく「どんな案件や働き方があるか」を日頃から見ていたことが、キャリアの選択肢を広げるきっかけになりました。
このブログを読んでくれた方に感謝を込めて、実際に使っている情報収集サービスを紹介します。

フルリモート・週3日・高単価、どんな条件も妥協したくないなら

フリーランスボードに無料会員登録する

利用者10万人以上。業界最大規模45万件の案件。AIマッチ機能や無料の相場情報が人気。

年収800万円以上のキャリアアップ・ハイクラス正社員を視野に入れているなら

Beyond Careerに無料相談する

内定獲得率90%以上。紹介先企業とは役員クラスのコネクションがある安心と信頼できるエージェント。


-Javascript