8.4 async/await構文
async/await は、Promise をベースとした非同期処理をより便利に、まるで同期処理のように上から下へと直感的に書くための強力な構文です。現代のTypeScriptプログラミングでは、then や catch メソッドよりもこちらが主流として使われます。
8.4.1 async関数を作ってみる
Section titled “8.4.1 async関数を作ってみる”関数の宣言の前に async キーワードを付けることで、その関数は「async関数」となります。
- 返り値は必ずPromise:
async関数の返り値の型は、必ずPromise<T>になります。 - 値の返却: 関数内で
returnした値が、そのまま返り値であるPromiseの「成功時の結果」となります。 - 例外の発生: 関数内で
throwなどにより例外が発生した場合、返り値のPromiseは「失敗」となります。
8.4.2 await式も使ってみる
Section titled “8.4.2 await式も使ってみる”await は、async 関数の中でのみ使用できる特殊な構文です。
- Promiseの待機:
await Promiseオブジェクトと記述すると、そのPromiseの結果が出る(解決される)まで関数の実行を一時中断して待ちます。 - ノンブロッキングな中断: この「待ち」はプログラム全体を止めるブロッキングではなく、
async関数の中の処理だけが中断し、その間は他の処理(呼び出し元の同期処理など)に制御が移ります。
8.4.3 awaitの返り値
Section titled “8.4.3 awaitの返り値”await 式は「式」であるため返り値があり、その値は 待機していたPromiseの成功時の結果 となります。
- 同期的な記述:
const num = await get3();のように、非同期処理の結果を変数に代入して次の処理に進むといった、同期プログラムと全く同じ制御フローで非同期処理を連鎖させることができます。
コラム 38 top-level await
Section titled “コラム 38 top-level await”原則として await は async 関数の中でしか使えませんが、比較的新しい機能として、モジュールのトップレベル(関数の中ではない一番外側の場所)でも await が使用できるようになりました(top-level await)。
- メリット: 即時実行関数(
main()など)を作らなくても、シンプルにトップレベルでファイルを読み込んだり、初期化を待ってからexportしたりすることが可能です。 - 環境: Node.jsの場合は v14.3.0 以降の対応など、比較的新しい実行環境とコンパイラ設定が必要です。
8.4.4 awaitとエラー処理
Section titled “8.4.4 awaitとエラー処理”await しているPromiseが失敗(reject)した場合、await 式の場所で例外が発生(throw と同じ扱い) します。
- try-catchの利用: この性質により、Promiseのエラー処理を
.catch()メソッドではなく、同期処理と全く同じtry-catch文を使って一元的にハンドリングすることができます。 - キャッチ漏れ: もし
try-catchでキャッチされなかった場合、その例外はasync関数の外側へ伝播し、最終的にasync関数自身が返すPromiseの「失敗」として扱われます。
8.4.5 async関数のいろいろな宣言方法
Section titled “8.4.5 async関数のいろいろな宣言方法”async function による宣言以外にも、以下の方法で async 関数を定義できます。
- async function式:
const func = async function() { ... }; - asyncアロー関数:
const func = async () => { ... };(外側のthisを引き継ぎます) - asyncメソッド記法: オブジェクトやクラスの中で
async method() { ... }のように記述します。