8.3 Promiseを使う
Promise は、ES2015で追加された非同期処理を扱うための機能です。非同期処理を行う関数はコールバック関数を直接受け取るのではなく、Promise オブジェクトを返すようになり、非同期処理をより抽象的・統一的に扱うことができます。
8.3.1 Promise版のfsを使ってみる
Section titled “8.3.1 Promise版のfsを使ってみる”Node.jsの fs/promises モジュールを用いると、Promiseベースの非同期APIを利用できます。
- Promiseの取得:
readFile("foo.txt", "utf8")のように呼び出すと、処理結果を待たずに即座にPromiseオブジェクト(Promise<string>型など)が返されます。この時点で既に非同期処理は裏で開始されています。 - thenメソッド: 返された
Promiseオブジェクトのthenメソッドにコールバック関数を渡すと、非同期処理が成功(解決)した際に、その結果を引数として関数が呼び出されます。
8.3.2 コールバック関数の登録とエラー処理(1)
Section titled “8.3.2 コールバック関数の登録とエラー処理(1)”Promise は処理の「成功」と「失敗」の2つの結果を持ちます。
catchメソッド: 処理が失敗(reject)した場合に呼び出されるコールバック関数を登録します。- エラーの型: 失敗時に渡されるエラー情報の型はTypeScript上ではデフォルトで
anyになるため、(error: unknown) => { ... }のように安全な型注釈をつけることが推奨されます。
8.3.3 コールバック関数の登録とエラー処理(2)
Section titled “8.3.3 コールバック関数の登録とエラー処理(2)”finallyメソッド: 成功・失敗のどちらの場合でも必ず呼び出されるコールバック関数を登録します。このコールバック関数は引数を受け取りません。
8.3.4 自分でPromiseオブジェクトを作る
Section titled “8.3.4 自分でPromiseオブジェクトを作る”既存のコールバック関数ベースの非同期処理を、自作の Promise に変換することができます。
- 構文:
new Promise<T>((resolve, reject) => { ... }) - 解決と拒否: 引数の
executor関数の中で非同期処理を行い、成功時にはresolve(結果)を、失敗時にはreject(エラー)を呼び出すことで、作られたPromiseオブジェクトの状態を確定させます。
8.3.5 Promiseの静的メソッド (1)
Section titled “8.3.5 Promiseの静的メソッド (1)”Promise.resolve(値): 与えられた値を結果として、即座に成功するPromiseオブジェクトを作ります。Promise.reject(値): 即座に失敗するPromiseオブジェクトを作ります。 (※即座に解決されたPromiseであっても、登録されたthenのコールバックは同期的な処理が全て終わった後、非同期的に実行されます。)
8.3.6 Promiseの静的メソッド(2)
Section titled “8.3.6 Promiseの静的メソッド(2)”複数のPromiseを組み合わせて新しいPromiseを作るメソッドです。
Promise.all: 渡されたPromiseの配列が「すべて成功」したら成功となり、それぞれの結果をまとめた配列を返します(1つでも失敗すると即座に全体が失敗します)。複数の非同期処理を並行して実行する際に非常に頻繁に使われます。Promise.race: 最も早く成功、または失敗したPromiseの結果を全体の結果とします。タイムアウト処理の実装などに有効です。
8.3.7 Promiseの静的メソッド (3)
Section titled “8.3.7 Promiseの静的メソッド (3)”Promise.allSettled: 成功・失敗に関わらず、すべてのPromiseの結果が出るまで待ちます。結果は各Promiseの成否ステータス(fulfilledかrejected)を含んだオブジェクトの配列となります。Promise.any: どれか1つでも成功した時点で成功となります。すべて失敗した場合にのみエラー(AggregateError)となります。
8.3.8 Promiseチェーン (1) チェーンを作る
Section titled “8.3.8 Promiseチェーン (1) チェーンを作る”then や catch メソッドは、呼び出されると「新しいPromiseオブジェクト」を作って返します。
- 値の変換:
thenのコールバック関数で値をreturnすると、それが新しく作られたPromiseの成功結果となります。 - 失敗のリカバリー:
catchのコールバック関数で値を返すと、元のPromiseの失敗を「成功」に変換して次のチェーンへ渡すことができます。 - これらを
p.then(...).catch(...)のように繋げて書く記法を Promiseチェーン と呼びます。
8.3.9 Promiseチェーン (2) 非同期処理の連鎖
Section titled “8.3.9 Promiseチェーン (2) 非同期処理の連鎖”then のコールバック関数で「別のPromiseオブジェクト」を返り値として返した場合、ネストは発生せず、返されたPromiseの結果が出るまでチェーン全体の解決が遅延します。これにより、非同期処理を順番に(直列に)連鎖させることができます。
8.3.10 Promiseチェーン (3) エラーの扱い
Section titled “8.3.10 Promiseチェーン (3) エラーの扱い”- エラーの発生:
thenの中でthrowを使って例外を発生させると、返されるPromiseは「失敗」となります。 - Unhandled Promise Rejection: 失敗したPromiseに対して
catch等でエラーハンドリングがされていないと、プロセスが強制終了してしまう致命的なエラーになります。 - 安全なチェーン:
p.then(...).catch(...)のようにチェーンの末端で確実にエラーをキャッチし、ハンドリング漏れを防ぐ設計が重要です。
8.3.11 dynamic import構文
Section titled “8.3.11 dynamic import構文”import("モジュール名") という構文で、モジュールを実行時に非同期で読み込むことができます。
- 結果: モジュールの名前空間オブジェクトを結果とする
Promiseが返されます。 - 用途: そのモジュールが必要になるまで読み込みを遅延させたい(遅延読み込み・コード分割)場合に重宝します。