【javascript】プロミス

この記事は以下の書籍を参考に執筆しました

- [入門JavaScriptプログラミング](https://www.amazon.co.jp/%E5%85%A5%E9%96%80JavaScript%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-JD-Isaacks/dp/479815864X/ref=sr_1_3?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=1F76CKY9CIJ66&dchild=1&keywords=%E5%85%A5%E9%96%80javascript%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0&qid=1595991879&s=books&sprefix=%E5%85%A5%E9%96%80javascript%2Cstripbooks%2C-1&sr=1-3)


プロミスでthenメソッドを呼び出すときには、引数として関数を渡し、この関数から返されるものはなんであってもチェンの次のthenの値になるが、

これには例外が1つある。

thenに渡された関数がプロミスを返す場合、そのプロミスは、値が解決または拒否されルマで待機してから同じことを行う。

```javascript
function wait(milliseconds) {
  return new Promise((resolve) => {
    setTimeout(resolve, milliseconds)
  })
}

const time = new Date().getTime()
const logTime = () => {
  const seconds = (new Date().getTime() - time)
  console.log(seconds / 1000, 'have elapsed')
}

wait(5000)
  .then(() => {
    logTime();
    return wait(5000)
  })
  .then(() => {
    logTime();
    return wait(2000)
  })
  .then(() => {
    logTime();
  })
```
>出典：[入門JavaScriptプログラミング](https://www.amazon.co.jp/%E5%85%A5%E9%96%80JavaScript%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-JD-Isaacks/dp/479815864X/ref=sr_1_3?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=1F76CKY9CIJ66&dchild=1&keywords=%E5%85%A5%E9%96%80javascript%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0&qid=1595991879&s=books&sprefix=%E5%85%A5%E9%96%80javascript%2Cstripbooks%2C-1&sr=1-3)

```
5.003 "have elapsed"
10.009 "have elapsed"
12.012 "have elapsed"
```

```javascript
  .then(() => {
    logTime();
     wait(5000)
  })
```
ここでは更に5秒待機するように設定されたプロミスを返す。
ここまでは合計で10秒待つことになる。
続いて2秒対して最後まで実行されるのに12秒かかる。

この方法がうまくいくのはthenに渡された関数がプロミスを返す場合に限られる。
下はプロミスを返さない場合。

```javascript
function wait(milliseconds) {
  return new Promise((resolve) => {
    setTimeout(resolve, milliseconds)
  })
}

const time = new Date().getTime()
const logTime = () => {
  const seconds = (new Date().getTime() - time)
  console.log(seconds / 1000, 'have elapsed')
}

wait(5000)
  .then(() => {
    logTime();
     wait(5000)
  })
  .then(() => {
    logTime();
     wait(2000)
  })
  .then(() => {
    logTime();
  })
```
>出典：[入門JavaScriptプログラミング](https://www.amazon.co.jp/%E5%85%A5%E9%96%80JavaScript%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-JD-Isaacks/dp/479815864X/ref=sr_1_3?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=1F76CKY9CIJ66&dchild=1&keywords=%E5%85%A5%E9%96%80javascript%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0&qid=1595991879&s=books&sprefix=%E5%85%A5%E9%96%80javascript%2Cstripbooks%2C-1&sr=1-3)



```
5.002 "have elapsed"
5.002 "have elapsed"
5.002 "have elapsed"
```
wait関数が返されていないため、待機しない。

##エラーキャッチ
thenの2つ目のパラメータにエラー時のコールバックを渡せるということは、数珠つなぎにした場合複数のエラーハンドラが必要なのか？

その必要はなく、プロミスが拒否された場合、そのプロミスは最初のエターハンドラが検出されるまでその上にあるプロミスをさかのぼる

```javascript
Promise.resolve()
  .then(() => console.log('A'))
  .then(() => Promise.reject('X'))
  .then(() => console.log('B'))
  .then(null, err => console.log('caught:', err))
  .then(() => console.log('C'))
```
>出典：[入門JavaScriptプログラミング](https://www.amazon.co.jp/%E5%85%A5%E9%96%80JavaScript%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-JD-Isaacks/dp/479815864X/ref=sr_1_3?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=1F76CKY9CIJ66&dchild=1&keywords=%E5%85%A5%E9%96%80javascript%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0&qid=1595991879&s=books&sprefix=%E5%85%A5%E9%96%80javascript%2Cstripbooks%2C-1&sr=1-3)


出力はこうなる

```
A
caught: X
C
```
Bが出力されていないことに注目
Bの出力はrejectとエラーハンドラの間で発生している。
しかしCは出力されている。

プロミスが拒否されると、そのことがキャッチされるまで、
その後にあるプロミスは解決されないから。

プロミスの拒否がキャッチされた時点で
それよりも後ろにあるプロミスの解決が可能になる。

```javascript
.then(null, err => console.log('caught:', err))
```
エラーハンドラを見てみると
1つの目引数に`null`が渡されている。
このステップではエラーをキャッチすることが唯一の目的だから。

そのためのメソッドとしてcatchがあり、それで書き換えると以下のようになる。

```javascript
Promise.resolve()
  .then(() => console.log('A'))
  .then(() => Promise.reject('X'))
  .then(() => console.log('B'))
  .catch(err => console.log('caught:', err))
  .then(() => console.log('C'))
```
>出典：[入門JavaScriptプログラミング](https://www.amazon.co.jp/%E5%85%A5%E9%96%80JavaScript%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-JD-Isaacks/dp/479815864X/ref=sr_1_3?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=1F76CKY9CIJ66&dchild=1&keywords=%E5%85%A5%E9%96%80javascript%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0&qid=1595991879&s=books&sprefix=%E5%85%A5%E9%96%80javascript%2Cstripbooks%2C-1&sr=1-3)


プロミスを拒否するためにPromise.rejectメソッドを使ったり、プロミス内部でrejectメソッドを呼ぶ必要はない。
Javascriptエラーが発生すればプロミスはすべて拒否される。

```javascript
Promise.resolve()
  .then(() => {throw 'My Error'})
  .catch(err => console.log('catch:', err))//catch: My Error
```
>出典：[入門JavaScriptプログラミング](https://www.amazon.co.jp/%E5%85%A5%E9%96%80JavaScript%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-JD-Isaacks/dp/479815864X/ref=sr_1_3?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=1F76CKY9CIJ66&dchild=1&keywords=%E5%85%A5%E9%96%80javascript%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0&qid=1595991879&s=books&sprefix=%E5%85%A5%E9%96%80javascript%2Cstripbooks%2C-1&sr=1-3)



別の例を見てみる

```javascript
ajax('/my-data.json')
  .then(
    res => {
      throw 'Some Error'
    },
    err => {
      console.log('First catcher:', err) //エラーがキャッチされない
    })
  .catch(err => {
    console.log('Second catcher:', err) //エラーがキャッチされる
  })
```
>出典：[入門JavaScriptプログラミング](https://www.amazon.co.jp/%E5%85%A5%E9%96%80JavaScript%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-JD-Isaacks/dp/479815864X/ref=sr_1_3?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=1F76CKY9CIJ66&dchild=1&keywords=%E5%85%A5%E9%96%80javascript%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0&qid=1595991879&s=books&sprefix=%E5%85%A5%E9%96%80javascript%2Cstripbooks%2C-1&sr=1-3)


thenに2つの関数を渡すと
1つ目の関数がプロミス解決時に実行
2つ目の関数がプロミス拒否時に実行される

しかし1つ目の関数でエラーが発生した場合、
**2つ目の関数はそのエラーをキャッチしない**

つまり、エラーをキャッチするには次のthenでキャッチしなくちゃいけない

#参考文献

- [入門JavaScriptプログラミング](https://www.amazon.co.jp/%E5%85%A5%E9%96%80JavaScript%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-JD-Isaacks/dp/479815864X/ref=sr_1_3?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=1F76CKY9CIJ66&dchild=1&keywords=%E5%85%A5%E9%96%80javascript%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0&qid=1595991879&s=books&sprefix=%E5%85%A5%E9%96%80javascript%2Cstripbooks%2C-1&sr=1-3)