今回は[[Promise (JavaScript)|Promise]]の異常系について学びます。 ## Reference - [非同期処理:Promise/Async Function · JavaScript Primer \#jsprimer](https://jsprimer.net/basic/async/) ## Lesson ### 失敗した処理のコード例 以下のコードは [[📗TDQ-024 Promiseの基本 正常系#コード例]] からコメントを消したものです。 ```js function createCapRamenPromise() { return new Promise((resolve) => { setTimeout(() => { resolve("美味しいラーメン"); }, 3 * 1000); }); } console.log("Before createCapRamenPromise"); createCapRamenPromise() .then((result) => { console.log(result); }); console.log("After createCapRamenPromise"); ``` `createCapRamenPromise` を必ず失敗するように変更し、例外処理を加えたコードは以下のようになります。 ```js function createCapRamenPromise() { return new Promise((_, reject) => { setTimeout(() => { // 非同期処理失敗時はPromiseコンストラクタの第2引数 rejectを使う reject(new Error("ラーメンはうまくできませんでした")); }, 3 * 1000); }); } console.log("Before createCapRamenPromise"); createCapRamenPromise() // 失敗時の処理はthenではなくcatchで受ける .catch((err) => { // err には createCapRamenPromise で reject(...) に指定した値が渡ってくる console.error(err); }); console.log("After createCapRamenPromise"); ``` 上記コードを実行すると、出力結果は以下のようになります。 ```console Before createCapRamenPromise After createCapRamenPromise Error: ラーメンはうまくできませんでした at file:///home/tadashi-aikawa/tmp/tdq/main.js:5:14 at callback (ext:deno_web/02_timers.js:58:7) at eventLoopTick (ext:core/01_core.js:212:13) ``` ## Mission 1 #🙂NORMAL 以下のコードが期待通りに動かない理由を説明してください。 ```js function createCapRamenPromise() { return new Promise(() => { setTimeout(() => { throw new Error("ラーメンはうまくできませんでした"); }, 3 * 1000); }); } console.log("Before createCapRamenPromise"); createCapRamenPromise() .catch((err) => { // ここで例外処理できない! console.error(err); }); console.log("After createCapRamenPromise"); ``` %% 解答例 非同期処理の中で発生した例外はグローバルスコープに伝播するため、[[Promise.prototype.catch (JavaScript)|Promise.prototype.catch]]では例外を捕捉できないから。 %% > [!hint]- Hint 1 > https://jsprimer.net/basic/async/#async-processing-and-error-handling ## Mission 2 #😁EASY [[#Mission 1]]のコードが期待通り動くようにコードを修正してください。 %% 解答例 ```js function createCapRamenPromise() { return new Promise((_, reject) => { setTimeout(() => { reject(new Error("ラーメンはうまくできませんでした")); }, 3 * 1000); }); } console.log("Before createCapRamenPromise"); createCapRamenPromise() .catch((err) => { console.error(err); }); console.log("After createCapRamenPromise"); ``` %% ## Mission 3 #🙂NORMAL [[#Lesson]]で作成した `createCapRamenPromise` を50%の確率で成功、50%の確率で失敗するようにしてください。成功時と失敗時でメッセージを出し分けてください。 %% 解答例 ```js function createCapRamenPromise() { return new Promise((resolve, reject) => { setTimeout(() => { Math.random() > 0.5 ? resolve("美味しいラーメン") : reject(new Error("ラーメンはうまくできませんでした")); }, 3 * 1000); }); } console.log("Before createCapRamenPromise"); createCapRamenPromise() .then((res) => { console.log(res); }) .catch((err) => { console.error(err); }); console.log("After createCapRamenPromise"); ``` %% --- *NEXT* >> [[📗TDQ-026 Promiseの並行処理]]