Promise嫌いを治したい。薄くまとめた本でとりあえずざっくりPromiseを復習してみた。

## はじめに
JS...。実を言うとあまり好きになれないのですよね。理由の一つは`Promise`なのかなと思っています。初学者の時に無理やり詰め込んで覚えたこちら。曖昧なところもあるまま`async`, `await`はもちろん、TSでも扱うようにしたら、自然と避けるようになってしまい。。。良くないので、これを機に全体をざっくり復習しようと思います。

## 使用テキスト
今回の使用テキストはこちらです。

https://www.amazon.co.jp/dp/4297103680

かの有名な[JS Primer](https://jsprimer.net/)の使用も考えたのですが、丁寧に記載がされすぎていて、かえってまとめるのが難しかったので。上記の[JavaScript コードレシピ集](https://www.amazon.co.jp/dp/4297103680)の方は、`Promise`~`async`, `await`を約20ページにまとめているので、非常に読みやすかったです！
引用したコードには基本的に引用元のページ数をつけています。

## 基本のPromise
### `then`で最初の処理に続く処理を記載できる
基本の`Promise`の処理はこんな感じ。①`resolve()`で1つ目の処理の完了させ、②`.then()`で続けて処理したい内容を記載します。

```js
const promise = new Promise((resolve) => {
  console.log("最初の処理", Date.now())

  setTimeout(() => {
    resolve(); // 最初の処理の完了
  }, 1000);
});

promise.then(() => { // then以降は最初の処理の1秒後に実行される
  console.log("次の処理", Date.now())
})
```
> JavaScript コードレシピ集 p.471 のコードに追記して使用

「最初の処理」が実行されてから1（=1000ミリ）秒後に「次の処理」が実行されます。
[![Image from Gyazo](https://i.gyazo.com/aa7dedb981c01fd2600327d15cdb915d.png)](https://gyazo.com/aa7dedb981c01fd2600327d15cdb915d)

### 間にブロックする処理を挟んでも、`then`に記載した処理は実行される
この時 **「最初の処理」** と **「次の処理」** の間に、それを **「ブロックする処理」** を挟み込みます。

```js
const promise = new Promise((resolve) => {
  console.log("最初の処理", Date.now())
  setTimeout(() => {
    resolve();
  }, 1000);
});

// ここを追加
setTimeout(() => {
  console.log("ブロックする処理")
}, 5000);

promise.then(() => {
  console.log("次の処理", Date.now())
})
```

通常なら、**「最初の処理」** → **「ブロックする処理」** → **「次の処理」** の順に処理が走りそうですが、
`promise`を使っていることで
**「最初の処理」** → **「次の処理」** → **「ブロックする処理」** の順に処理が走ります。

[![Image from Gyazo](https://i.gyazo.com/ea9d739084b575fe47a3f35a1c7a2086.png)](https://gyazo.com/ea9d739084b575fe47a3f35a1c7a2086)

## Promiseで指定した処理にエラーが出たら`catch`で続けることができる
`Promise`の中で記載した処理に失敗した時には、`catch`を使って処理を続けることができます。
次のコードだと、1/2の確率で`flag`は`true`ではなくなり、「失敗時の処理」がコンソールに出力されます。

```js
const flag = Math.random() < 0.5 && true
const promise = new Promise((resolve, reject) =>{
  if (flag === true) {
    resolve('成功時の処理');
  } else {
    reject('失敗時の処理');
  }
})

promise.then((value) => {
  console.log(value)
})

promise.catch((value) => {
  console.log(value)
})
```
> JavaScript コードレシピ集 p.473 のコードを改変して使用

失敗時にはこのようにコンソールに表示されるのですが、どうしてエラー文まで出るのかは謎です。
[![Image from Gyazo](https://i.gyazo.com/5aaa4344a4f796a83a3e7c93f61427a7.png)](https://gyazo.com/5aaa4344a4f796a83a3e7c93f61427a7)

## 直列処理と`async`, `await`
### まずはサンプルコード
`.then`でメソッドチェーン的にPromiseの処理を続けて書くことができます。

```js
Promise.resolve()
  .then(
    () =>
      new Promise((resolve) => {
        setTimeout(() => {
          console.log('1つ目のPromise', new Date().toLocaleTimeString());
          resolve();
        }, 1000);
      })
  )
  .then(
    () =>
      new Promise((resolve) => {
        setTimeout(() => {
          console.log('2つ目のPromise', new Date().toLocaleTimeString());
          resolve();
        }, 1000);
      })
  )
```
> JavaScript コードレシピ集 p.477 のコードを抜粋

そして、直列処理のpromiseは`async`, `await`構文を使うとより簡潔に書けます。

```js
async function start() {
  await new Promise((resolve) => {
    setTimeout(() => {
      console.log('1つ目のPromise', new Date().toLocaleTimeString());
      resolve();
    }, 1000);
  })

  await new Promise((resolve) => {
    setTimeout(() => {
      console.log('2つ目のPromise', new Date().toLocaleTimeString());
      resolve();
    }, 1000);
  })
}

start();
```
> JavaScript コードレシピ集 p.478 のコードを抜粋

### 詳細確認

わーい、簡単♪ ...と思いきや、謎もやはり多いですよね。まずはこの部分。

```js
Promise.resolve()
  .then(
    () =>
      new Promise((resolve) => { // ←引数resolveとは？
        setTimeout(() => {
          console.log('1つ目のPromise', new 
     //... 以下略
```
突如出てきたように見える、引数の`resolve`ってなんやねん！？ってなりませんでしたか？（私はなりました）。
**`Promise`では、直前の`Promise`の成功時に返された値を、次の`then`の引数として使えるそう**なので、その値です。
なので、次のような直列処理の式も成立します。

```js
Promise.resolve(1) // ここのresolveは成功時に１を返すpromiseを作る
  .then((value) => {
        console.log(value); // 1が表示される
        return value * 2
      })
  .then(
    (value) => {
      console.log(value);  // 2が表示される
      return value * 2
    })
```
> JavaScript Primer P.277 のコードを改変して使用

そして、`async`, `await`構文についてですが、まず、
- `await`は右辺の式が実行されるまで次の処理を待つ機能です
- `async`は`promise`インスタンスを返すメソッドです。

なので、こちらの`async`構文は**一つ目のPromiseを行なって、二つ目のPromiseを実行するという一連の処理の流れを持ったPromiseインスタンスを返す**構文となります。

```js
const start = async () => {
  await new Promise((resolve) => {
    setTimeout(() => {
      console.log('1つ目のPromise', new Date().toLocaleTimeString());
      resolve();
    }, 1000); // 1. この処理が終わったら
  })

  await new Promise((resolve) => {
    setTimeout(() => {
      console.log('2つ目のPromise', new Date().toLocaleTimeString());
      resolve();
    }, 1000); // 2. この処理を実行して
  })
}

start(); // 1~2の一連の流れが詰まったメソッド
```

## まとめ
以上となりましたが、ざっくりと`Promise`の流れを復習しました。今だからわかることも多いけど、初学者の時には分かりにくかったこともあり、やはり定期的に復習は大事だなと思いました。

手元にあるTSの書籍についても非同期処理の記述があるので、引き続きTSにおけるPromiseの扱いについて復習したいと思います。