JavaScript Promiseオブジェクトを使った非同期処理の初歩

# 概要
JavaScriptで同期/非同期処理をやるときに避けられない、`Promise`オブジェクトについて書いておきます。
書く目的は、自分がまた忘れてしまったときに振り返るためと、私と同じくらいのレベルの方の理解の補助になれば。（いろいろな書き方や資料がある中で、自分に刺さる例ってあると思うので）

なお`(x) => x*2`は`function(x){return x*2;}`の省略形です。自然に使える前提で書いてます。

## 参考
- [Promise - JavaScript | MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)

# Promiseオブジェクトの理解
## step1：遅い計算の実行
Promiseオブジェクトは、その中に関数を書いて定義すると、"そのうち"やってくれるもの。
例えば、
```javascript
let p1 = new Promise((resolve, reject) =>
{
  resolve(1+2)
})
```
こうやって書くと、`1+2`の処理を実行してくれます。`resolve`関数に引数の結果を詰めて呼ぶと、`p1`の中に格納されます。（`1+2`が遅い計算だとしてください。）
呼び出した側は、`Promise`オブジェクトが`new`されて、それが`p1`に格納されるところまでは、するっと行きます。p1に代入した後に別の処理があればどんどん進みます。でも`1+2`はまだ計算されません。`1+2`の部分がすごく遅い場合、例えばHTTPアクセスして情報を取得するとかの場合でも、同じです。つまりこの部分が非同期で動くということ。
> →→メインの処理→→→→→→→・・・
> 　　　└ Promiseの中の処理"1+2"が、メインと非同期で動く

## step2：結果の利用
次にこの`1+2`の結果をどう扱うかというと、こんな感じ。
```javascript
let p1 = new Promise((resolve, reject) =>
{
  resolve(1+2)
}).then((data) => {  // 追加
  console.log(data)  // 追加
})                   // 追加
// 3
```
`.then()`を追加して、その中に関数を書いてます。引数の`data`に、`resolve()`に渡した引数、`1+2`の結果である`3`が格納されています。その`3`を使って、次の処理である`console.log()`をしています。
> →→メインの処理→→→→→→→・・・
> 　　　　└ "1+2"の計算処理 → then()の中の処理

## step3：さらにその次もやりたい！
２つだけでなく、どんどん続けたくなると思います。その場合はこうします。
```javascript
let p1 = new Promise((resolve, reject) =>
{
  resolve(1+2)
}).then((data) => {
  console.log(data)
  return new Promise((resolve, reject) =>  // 追加
  {                                        // 追加
    resolve(data+4)                        // 追加
  })                                       // 追加
}).then((data) => {                        // 追加
  console.log(data)                        // 追加
})                                         // 追加
// 7
```
step2で追加した`then()`の中で、別の`Promise`オブジェクトを作ってそれを`return`します。その`Promise`ので`resolve()`に値を入れてやると、その次の`then()`で使えます。
> →→メインの処理→→→→→→→・・・
> 　　　　└ "1+2"の計算処理 → then()の中で"3+4" → ２つ目のthen()の中の処理でdataは7

## step1～3のまとめ
非同期処理を想定した`1+2`ですが、そのあと順番に`then()`→`then()`となって、結局同期処理なんじゃないか？と私は混乱しました。そうなんです。非同期処理を、順番に起動してます。非同期処理を同期的に実行していると言っていいのかな。私はそういうイメージです。`Promise`と`then`を使うことで、例えば、最初の`Promise`でHTTPアクセスのようにすべて取得し終えるのを待ち終わったらコールバック関数で`resolve()`に結果を詰めれば、その次の`then`で、HTTPアクセスの結果を利用できます。

なんか、、これ↑、わかってる人にはわかるけど、わからない人にはわからないという文章になってそうな気がするので、次にちゃんと時間がかかる簡単な例を書きます。

# f(x)=2*x+5の実装例（ただし`2*x`は３秒かかるとする）
３つの関数を定義して、それを呼び出す例です。

## ２倍する関数の実装
まずこの関数を定義します。３秒かかるようにしてあります。
```javascript
function calc_double(x) {
    return new Promise((resolve, reject) =>
    {
        try {
            setTimeout(() => {
                resolve(x*2)
            }, 3000)
        } catch (err) {
            reject(err)
        }
    })
}
```
`setTimeout`は、最初の引数の処理を、２つ目の引数のミリ秒後に実行します。なので、３秒後に`x*2`を実行して、その結果を引数に`resolve`を実行します。これで、３秒かかる2*xの関数が完成。
`setTimeout`は、非同期処理の説明ですごくよく出てくる関数なので、動きがわからなければこれを機会に簡単な例を自分で作って完全理解することをお勧めします。システムとかの実装では頻繁には使わないかもだけど。

最初のstep1～3ではあえて説明しなかった`reject`ですが、`resolve`の代わりに`reject`を呼ぶとエラーで止まるという仕組みです。引数にエラーの情報を入れると吉。

## ＋５する関数の実装
今度は待たずに`x+5`しているだけなので単純です。`Promise`や`try`,`catch`してるのが煩わしいですが。
```javascript
function calc_plus5(x) {
    return new Promise((resolve, reject) =>
    {
        try {
            resolve(x+5)
        } catch (err) {
            reject(err)
        }
    })
}
```

## f(x)=2*x+5の実装
最後の関数で、`calc_double`を呼び出し、そのあと`then`で`value`を`calc_plus5`に入れてます。
```javascript
function calc_2x_plus5(x) {
    return calc_double(x)      // （１）
        .then(value => calc_plus5(value))   // （２）
}
```
（１）の部分は、`calc_double`の定義から`(new Promise((resolve,reject)=>resolve(x*2)))`だな、つまり`x*2`を計算する`Promise`が返ってくると見ます。
（２）の部分は、`x*2`を計算した`Promise`の`then`なので、`value`は`x*2`の結果が入っていて、それを`calc_plus5`に渡すと。そして`calc_plus5`も`new Promise`を`return`してます。
結局全体の`return`としては、`calc_plus5`の`Promise`オブジェクトが返る関数になります。

関数を定義したことでちょっとわかりづらかったかもしれませんが、処理を境目を理解するにはその方がよいと思っています。また実際に使う場面でも、やっていることの理解がしやすいと思います。まずは2倍、つぎに+5かーといった具合に。

## 使い方
普通の関数のようにはいきません。使うときも、`then`で結果を取り出します。3を入れれば11、5を入れれば15が表示されます。
```javascript
calc_2x_plus5(3).then(v => console.log(v))
// 11
calc_2x_plus5(5).then(v => console.log(v))
// 15
```
ちなみに`2*x`に３秒かかる処理なのですが、１行目の`calc_2x_plus5(3)`が流れた直後に２行目の`calc_2x_plus5(5)`も流れます。つまりこんな感じ。
> →→メインの処理→→→→→→→・・・
> 　│└ `2*5`で３秒待ち→→→`10+5=15`
> 　└ `2*3`で３秒待ち→→→`6+5=11`

`2*3`を計算し始めた直後に`2*5`を計算し始めます。ほぼ同時。なので３秒後に結果が出るのもほぼ同時です。６秒後ではありません。

## 実践の話
メインの処理と`Promise`で世界線が分かれてしまったので、もう二度と出会うことがないかというとそうではなく、`Promise`の世界線から、メインの変数にアクセスできます。またJavaScriptの場合だと、HTML上で何かのアクションをすることもあると思います。実際にはそうやって使います。

# まとめ
Promiseの初歩は、なかなか敷居の高い１歩です。私自身、１歩上ったような、上らないような感覚ですが、いくつか実装したりいろんな説明を見たりして身に着けていきましょう。

触れなかった話として、`Promise`コンストラクタに関数を入れて、その引数が２つあって、それに値を詰めて呼び出す、というところがあります。普通のプログラミングのように上から順に流れる処理からすると、この部分が直感的にすごくわかりづらい！なのであえて触れませんでした。とりあえずおまじないだと思っておけばよいのではないでしょうか。動きやなすべきことがわかってきたら、ちゃんとした資料やサイトを読みましょう。