ajaxで非同期通信とかを頑張った話

#この記事について
Javascriptがぜんぜん解らない()駆け出しフロントエンジニアが、勉強目的で触ったajaxのまとめです。

##対象者
1. これからJavascriptを触る人
2. pureなJavascriptで非同期通信処理をやろうとしている人
3. 未来に存在しているであろう、ど忘れしている私へ

#そもそもAjaxとはなんぞや
###**[Asynchronous JavaScript + XML]**
その名の通り、JavascriptとXMLを使った非同期通信。
XMLに送るデータ内容を記述し、JavascriptのAPIであるXMLHttpRequestを使って、サーバー側にデータ送信する処理の事です。
ただ、最近はもうXMLを使わずにJSONにデータを記述することが多い。

###pureなJavascriptだとどうコーディングするの？
```Javascript:main.js
        let xhr = new XMLHttpRequest();
        xhr.open('POST','hogehoge.php',true);
        xhr.setRequestHeader('content-type','application/x-www-form-urlencoded;charset=UTF-8');
        xhr.send(
            //送りたい内容を記述
        );
        xhr.onreadystatechange = function()
        {
           //サーバーからの応答に応じた処理
        }
```
各メソッドに対しての説明は省略しちゃいます。
詳しくは[MDN](https://developer.mozilla.org/ja/docs/Web/API/XMLHttpRequest)の方で。

これを、初期読み込み時にサーバーからデータを取得してきたり、
更新ボタンを押下したときのイベント処理の中に組み込んだり…と使っていきます。

##ただし、問題が…
JavaScript はシングルスレッドで動くため、当然ながら`send`メソッドでデータをサーバー側に送信した後は、後続の処理を引き続き行われます。

```Javascript:main.js
        let xhr = new XMLHttpRequest();
        xhr.open('POST','hogehoge.php',true);
        xhr.setRequestHeader('content-type','application/x-www-form-urlencoded;charset=UTF-8');
        xhr.send(
            //送りたい内容を記述
        );

        xhr.onreadystatechange = function()
        {
           //サーバーからの応答に応じた処理
        }

        alert('りんご')
```
このような場合、`send`メソッド実行後は`alert`が実行され、りんごがアラートで表示されちゃいます。
当然ながら、そこでHTTP通信で返されてきた結果を扱いたいとしても、まだ`onreadystatechange`内に結果は返されていないはずなので、クリティカルなことになっちゃいます。
えらいこっちゃ…。
なので、こうしちゃいます。

```Javascript:main.js
        xhr.onreadystatechange = function()
        {
            if(xhr.readyState = 4 && xhr.status == 200)
            {
               alert(xhr.responseText)
            }
        }
```
これで、サーバーから帰ってきたデータを扱うことができます。
やったね！

##ただ…
この非同期処理を連続で行って行きたい場合はどうなるかというと…

```Javascript:main.js
let xhrA = new XMLHttpRequest();
//設定とかの処理
xhrA.onreadystatechange = function()
{
    if(xhrA.readyState = 4 && xhrA.status == 200)
    {
        let xhrB = new XMLHttpRequest();
        //設定とかの処理
        xhrB.onreadystatechange = function()
        {
            if(xhrB.readyState = 4 && xhrB.status == 200)
            {
                let xhrC = new XMLHttpRequest();
                //設定とかの処理
                xhrC.onreadystatechange = function()
                {
                    if(xhrC.readyState = 4 && xhrC.status == 200)
                    {
                        //続く…
                    }
                }
            }
        }
    }
}
```

わぁ、ネストの宝石箱やー。
これはもう見るだけで拒否感が出てしまいますね。
当然ながら、色々処理を省いてこれなので実際に運用するとさらに可読性が下がっていっちゃいます。
ヤバイですね☆


##解決方法
###その1 Callback
callbackで実装する。
ES6(ES2015)以前で主に使われていた手法です。
問題のコードよりかはわかりやすくなりますが、callbackもコールバック地獄というネストが深くなる問題を抱えてるので、
ブラウザ側も最新のJS仕様に対応してきているので、最近では使用されないことが多いのと思います。

###その2 Promise
今回私が使ったのがこれでした。
ES6(ES2015)で実装された仕様。
[Promiseを使う](https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Using_promises)
>Promiseは非同期処理の最終的な完了もしくは失敗を表すオブジェクトです。

```Javascript:main.js
function promiseFunction()
{
    return new Promise((resolve,reject) =>
    {
         //非同期で行いたい処理をここに記述する
    })
}
```
成功した場合は`resolve`メソッドを呼び出すことで処理が終わったことを、呼び出し元に伝えることができます。
また、promiseではpromiseチェーンを使うことで、非同期処理を連続して行うことができます。

```Javascript:main.js
promiseFunction().then(() =>
{
    return promiseFunction();
})
.then((result) => 
{
    return promiseFunction();
})
.then((result) => 
{
    return promiseFunction();
})
.catch((err) =>
{
   console.log('エラー');
});
```
`then`の中で次に行いたいpromiseオブジェクトを呼び出すことで、処理をつなげることができます。
callbackやpureな実装時よりも、かなり直感的でシンプルになりました。

###その3 async/await
ES2017で実装された仕様。
Promiseよりチェーンをなくし、よりシンプルでわかりやすくなった非同期処理です。
[async/awaitで非同期処理はシンプルになる](https://qiita.com/ryosukes/items/db8b45c8ea42f924f02f)
[async/awaitを使ったモダンな非同期処理](https://qiita.com/rana_kualu/items/f3dfcb8e7ef0cc9955d6)

とはいえ全く別物というわけではなく、非同期処理の部分ではPromiseを使用しています。

##どれを使えばいいの？
`async/await`を使えばいいと思います。
私は先にPromiseを見つけた関係でそちらを使いましたが、よりモダンにするなら`async/await`一択と思われます。
ただ、`Promise`も使う場合があると思いますので、どっちも使えるようになっておくといいかな。

#終わりに
長くなってしまいましたが、pureなajaxを頑張ってみた記事でした。
これからpureな非同期処理をやる方に、少しでも情報を伝えることができたなら幸いです。

###参考記事
[MDN](https://developer.mozilla.org/ja/docs/Web/API/XMLHttpRequest)
[Promiseを使う](https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Using_promises)
[async/awaitで非同期処理はシンプルになる](https://qiita.com/ryosukes/items/db8b45c8ea42f924f02f)
[async/awaitを使ったモダンな非同期処理](https://qiita.com/rana_kualu/items/f3dfcb8e7ef0cc9955d6)