Promiseを理解する

通信やファイル読込みの結果はすぐには得られないことがあります。Promiseは、後で成功値または失敗理由が決まる処理を表します。単に待つ道具と覚えず、状態・戻り値・コールバックの実行順序を読みます。

この単元で学ぶこと

  • Promiseの状態と一度だけの確定を説明できる
  • thenの戻り値と例外の伝播を追える
  • 同期処理とPromise反応の順序を区別できる

本文解説

三つの状態 Promiseはpending(結果未確定)、fulfilled(成功)、rejected(失敗)の状態を持ちます。fulfilledまたはrejectedになると、その状態から別の状態へ変わりません。成功後にrejectを呼んでも、先の成功を取り消す操作にはなりません。

作成時の処理 「new Promise((resolve,reject)=>{ resolve(3); })」は値3へ成功するPromiseです。この関数(executor)はコンストラクター呼出し時に同期的に実行されます。Promiseで包んだだけで重い計算が別スレッドへ移るわけではありません。

thenによる後続処理 「Promise.resolve(3).then(x=>x+2)」のthenは新しいPromiseを返し、それは5へ成功します。元のPromiseの値を5へ書き換えるのではありません。ハンドラーが値をreturnすればその値、returnしなければ通常undefinedが次の成功値になります。

Promiseを返す場合 thenのハンドラーから別のPromiseをreturnすると、後続Promiseはその結果を引き継ぎます。「then(x=>Promise.resolve(x*2))」ならその成功値が次へ渡ります。非同期処理を呼ぶだけでreturnしなければ、後続がその完了を待つ連鎖にはなりません。

実行順序 「console.log("A"); Promise.resolve().then(()=>console.log("B")); console.log("C");」はA、C、Bの順です。既に成功したPromiseでもthenのハンドラーは現在の同期コードが終わった後に実行されます。executorが同期である点と分けて覚えます。

失敗と回復 ハンドラー内でthrowすると、返されたPromiseはその例外を理由に失敗します。catchは失敗を受け取るハンドラーです。「Promise.reject("E").catch(()=>0)」は失敗を処理して値0へ成功する新Promiseを返します。catchで再びthrowすれば失敗が続きます。

allで複数結果を集める Promise.all([p1,p2])は全て成功すると入力順の結果配列へ成功します。終了が早い順には並びません。一つ失敗すると返されるPromiseは失敗しますが、他の処理を自動的に停止する保証はありません。Promise.all([])は空配列の成功を表します。

finallyの位置付け finallyは成功・失敗のどちらでも後片付けを行いたい場合に使います。通常値を返すだけなら元の成功値や失敗理由を置き換えません。ただしfinallyが例外を投げたり失敗Promiseを返すと、その失敗が後続へ伝わります。値を変換したい処理はthen等と分けます。

図解

結果の確定と連鎖
元の状態変化と後続Promiseの状態を分けて読みます。

重要ポイント

  • executorは同期、thenハンドラーは後で実行。
  • thenは新しいPromiseを返す。
  • returnの有無で後続値や待合せが変わる。
  • allの結果は入力順、失敗しても他処理を自動停止しない。

間違えやすい点

  • PromiseでCPU処理が自動並列化すると考えない。
  • catchが常に失敗のまま返すと思わない。
  • finallyの普通のreturnで成功値を変更できると思わない。

用語解説

executor
new Promiseに渡し、成功・失敗を通知する関数。作成時に同期実行される。
fulfilled
Promiseが成功値を持って確定した状態。
rejected
Promiseが失敗理由を持って確定した状態。

関連教材

参考資料

教材データに登録された参考リンクです。リンク先の内容や更新日は提供元でご確認ください。

確認問題の出題・採点や学習履歴の保存にはログインが必要です。