Promiseのブラウザ挙動/実装演習
Promiseの短いコードを追い、どの値が次へ渡るか、失敗がどこで回復するかを確認します。同期ログと非同期ハンドラーを二列に分けて考えると順序を誤りにくくなります。
この単元で学ぶこと
- executorとthenのログ順序を予測できる
- return・throw・catchによる連鎖結果を計算できる
- all・raceの結果条件と取消しの違いを説明できる
本文解説
作成と反応の順序 「log("A"); const p=new Promise(r=>{log("B");r(2);}); p.then(x=>log(x)); log("C");」はA,B,C,2です。executorのBは作成中に同期実行され、thenの2は現在の同期処理が終わった後に出ます。
値を連鎖する 「Promise.resolve(2).then(x=>x*3).then(x=>x+1)」は最終的に7へ成功します。各thenが別のPromiseを返し、6を次へ渡すためです。最初を「x=>{x*3;}」へ変えるとreturnがなく、次はundefined+1でNaNになります。
失敗から回復 「Promise.resolve(2).then(()=>{throw new Error("bad");}).catch(()=>10).then(x=>x+1)」は11へ成功します。catchが10を返すことで成功へ戻っています。catchでエラーを記録するだけなら通常undefinedへ成功するので、失敗を継続したい場合は再throwします。
同じthenの失敗ハンドラー 「p.then(success,failure)」のfailureはpの失敗を受けます。successの内部で発生した例外は、この同じthenのfailureではなく、thenが返すPromiseの失敗となります。その後へcatchをつなぐと受け取れます。
戻り値を返す意味 「then(()=>fetchData())」なら返したPromiseの完了を次が待ちます。「then(()=>{fetchData();})」ではreturnがなく、次は通常undefinedを受け、fetchDataの完了を連鎖として待ちません。処理を呼んだことと、依存関係へ組み込んだことを区別します。
allの配列 入力がPromise.resolve(2)、Promise.resolve(5)ならallの結果は[2,5]。通常値3とPromise.resolve(4)を渡しても[3,4]へ成功します。一つの失敗で結果全体は失敗になりますが、他の通信が取り消されるとは限りません。
raceの意味 Promise.raceは最初に確定した結果を引き継ぎ、成功限定ではありません。先に失敗したPromiseがあればraceも失敗します。タイムアウト通知に使っても、元の通信を自動的に取消す操作ではありません。取消しにはそのAPIの手段を別に用います。
finallyの例外 「Promise.resolve(2).finally(()=>{throw new Error("cleanup");})」は後片付けの例外で失敗します。一方finallyが通常値9を返すだけなら成功値2を保ちます。「常に結果へ影響しない」と覚えず、正常終了と例外を分けて判断します。
図解
重要ポイント
- executorのログは同期、thenのログは後。
- returnしないブロックの後続値は通常undefined。
- 同じthenの失敗ハンドラーは成功ハンドラー自身の例外を捕捉しない。
- raceは最初の成功ではなく最初の確定。
間違えやすい点
- Promiseを開始するだけで後続が待つと思わない。
- raceの失敗や自動取消しなしを見落とさない。
- finallyのthrowを無視しない。
用語解説
- 連鎖
- ハンドラーの戻り値や失敗を次のPromiseへ引き継ぐこと。
- race
- 入力のうち最初に確定する成功または失敗を引き継ぐ合成。
関連教材
参考資料
教材データに登録された参考リンクです。リンク先の内容や更新日は提供元でご確認ください。
確認問題の出題・採点や学習履歴の保存にはログインが必要です。