javascriptの非同期処理について理解する

##　そもそも同期処理とは
プログラムに記述された順序通りに実行される実行方式。

### 同期処理サンプルプログラム
```javascript:synchronous.js
const calculate = () => {
    return 1 + 1
}

const message = "1+1="
const result = calculate()
console.log(message + result)
```

実行結果

```
$ node synchronous.js 
1+1=2
```

上の例は問題ないが、もし`calculate`関数がとても時間のかかる処理であれば、ユーザーにとって大きな待ち時間が生まれる。
それを解決するために非同期処理が存在する。


## 非同期処理とは
タスクの実行完了を待たず、並行して次の処理を行う実行方式。
インターネットを通じて外部のデータを操作するとき（Web Apiを叩く）や、データベースにクエリを発行する際に利用される。
身近にある非同期処理が使われたサービスは、Google Mapである。Google Mapは地図の読み込み時にもユーザーは操作できる。
ここでは、非同期処理を使ってgithubの提供するAPIを叩いてユーザー名を取得させるプログラムを書いてみる。


### 非同期処理サンプルプログラム
```javascript:asynchrounous.js
import fetch from 'node-fetch'

const getUserName = () => {
    const url = "https://api.github.com/users/XXXXXXXXX" //XXXXXXXにはgithubのユーザー名を入れてください

    fetch(url).then(res => res.json()) //非同期処理であるfetchメソッドで定義したurlからデータを取得して、取得したデータを引数（res）としてjsonメソッドでjson化する処理をthenメソッドでチェーン
        .then(json => { //成功時にres.json()の戻り値を引数(json)として処理を記述
            console.log("これは非同期処理成功時のメッセージです")
            console.log(json.login) //ユーザー名を表示
            return json.login //ユーザー名を戻り値としてgetUserNameにreturn
        }).catch(error => { //失敗時の処理
            console.log("これは非同期処理失敗時のメッセージです", error)
            return null
        })
};

const message = "githubユーザー名:"
const userName = getUserName()
console.log(message + userName)
```

実行結果

```
githubユーザー名:undefined
これは非同期処理成功時のメッセージです
XXXXXXXXXX
```
※XXXXXXXXにはgithubユーザー名が入ります。
githubユーザー名が`undefined`と表示されてしまった。
これは、`fetch`が非同期で処理するメソッドであるために、`getUserName`関数の処理が完了して`UserName`に結果が代入される前に`console.log(message+userName)実行されたからである。
これを解決するために、この**非同期処理を、同期処理のように実行順序を制御する必要がある。**
2通り方法がある。
Promiseを使う方法、async/awaitを使う方法である。
どちらの方法も**非同期の処理が完了するまで次の処理に進まないようにしてくれるものである。**

## Promiseを使う方法

### Promiseサンプルプログラム
```javascript:promise.js
import fetch from 'node-fetch'

const getUserName = () => {
    return new Promise((resolve, reject) => { //new PromiseでPromiseのインスタンスを作成、その引数にresolve,rejectを引数にした非同期処理の関数を記述
        const url = "https://api.github.com/users/XXXXXXXX" //XXXXXXXにはgithubのユーザー名を入れてください

        fetch(url).then(res => res.json()) //非同期処理であるfetchメソッドで定義したurlからデータを取得して、取得したデータを引数（res）としてjsonメソッドでjson化する処理をthenメソッドでチェーン
            .then(json => { //成功時にres.json()の戻り値を引数(json)として処理を記述
            console.log("これは非同期処理成功時のメッセージです")
                console.log("非同期処理が成功")
                return resolve(json.login) //ユーザ名をreturn
            }).catch(error => { //失敗時
                console.log("非同期処理失敗", error)
                return reject(null)
            })
    })
};

const message = "githubユーザー名:"
getUserName().then(userName => { //成功すればthenメソッドが実行される。userNameにはgetUserName関数のjson.loginが入っている。
    console.log(message + userName)
}).catch(()=>{ //失敗すればcatchメソッドが実行される
    console.log("rejectしました")
})
```

実行結果

 ```
$ node promise.js 
非同期処理が成功
githubユーザー名:XXXXXXXXX
```

`Promise`を使うことで非同期処理内（この例では`fetch`メソッド以下）で`resolve`または`reject`が出てくるまで次の処理に進まないようにしてくれる。

#### Promiseには3つの状態がある
`Promise`には、`PromiseStatus`という3つのステータスがある。
* `pending`: 初期状態（未処理）
* `resolved`: 成功状態
* `rejected`: 失敗状態

`new Promise`で作られた`Promise`オブジェクトの`PromiseStatus`は`pending`（初期状態）となり、成功した場合は`resolved`(成功状態)となり、失敗した場合、`rejected`（失敗状態）となる。`resolved`の場合は`then`メソッドが実行され、`rejected`の場合は`catch`メソッドが実行される。

## async/await

### async/awaitサンプルプログラム
```javascript:AsnycAwait.js
import fetch from 'node-fetch'

const getAddress = async() => { //非同期処理を伴う関数定義時の引数をasync()にする
    const message = "githubユーザー名:"
    const url = "https://api.github.com/users/XXXXXXXX" //XXXXXXXにはgitのユーザー名を入れてください

    const json = await fetch(url) //非同期処理を伴う関数実行時にawaitをつける
        .then(res => { //成功時にfetchメソッドで取得したデータを引数として処理を記述
            console.log("非同期処理成功")
            return res.json() //resをjson化
        }).catch(error => { //失敗時の処理
            console.log("非同期処理失敗", error)
            return null
        });

    const userName = json.login //ユーザー名を代入
    console.log(message + userName)
}

getAddress()
```
実行結果

```
$ node AsyncAwait.js 
非同期処理成功
githubユーザー名:XXXXXXXX
```

非同期処理を伴う関数定義の引数を`async()`にして、非同期処理を伴う関数実行時に`await`をつけることによって非同期処理が完了するまで次の処理に進まないようにしてくれる。

## 参考
[【ES6】 JavaScript初心者でもわかるPromise講座](https://qiita.com/cheez921/items/41b744e4e002b966391a)
[非同期処理の完了を待つ方法！Promise＆async/await【分かりすぎて怖いJavaScript入門】](https://www.youtube.com/watch?v=Vhnz1V-v1cU)