今回は[[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の並行処理]]