jQuery ではなくFetchAPIを使用してAJAX通信をおこなう

# はじめに
昔はブラウザ間の互換性に問題があったため、互換性を解決してくれるjQueryがはやりました。
が時代がたつとブラウザ間の互換性は解決され、dom操作も簡単にできるようになりました。
またフレームワーク(Angular,Vue.js,React)が登場しバージョン間の問題もあり新規でjQueryを導入するメリットがなくなってきました。
そのため脱JQueryに向け、よく使用されていると思われるAJAX通信をjavascriptのFetch APIに置き換えるための基本的な使い方をメモとして残します。

# 単純な例
jsonを返す単純なphpを用意
```php:json_test.php
<?php
// テスト用
sleep(3);
?>
{"foundation": "Mozilla", "model": "box", "week": 45, "transport": "car", "month": 7}
```

fetchを使用して呼び出し
```Javascript:test.html
ajax_test();

function ajax_test() {
    fetch("./json_test.php")
        .then(response => {
            return response.json();
        })
        .then(json => {
            console.log(json);
        });
}
```
thenをチェーンメソッドでつなげ
最初のthenでjsonを受け取りデコード
jsonの結果を次のthenでコンソールに出力

# async、awaitを使用した例
単純な例では非同期で行っていたが、async、awaitを使用することにより
プロミスを返す関数の処理を待機させ直列で動作（同期っぽく）させることができる。

```Javascript:test.html
    async_ajax_test();

    async function async_ajax_test() {
        const response = await fetch("./json_test.php");
        const json = await response.json();
        console.log(json);
    }
```
関数にasyncを付けfetchをするときにawaitをして処理を待機させる。
詳しい事は下記が参考になります。
https://qiita.com/jun1s/items/ecf6965398e00b246249

## 上記だけだとわかりづらいので例

最初に用意したjsonを返す単純なphpをsleepしないバージョン
```php:json_test2.php
{"foundation": "Mozilla", "model": "box", "week": 45, "transport": "car", "month": 7}
```

### 非同期で呼び出し
```Javascript:test.html
ajax_test();
ajax_test2();

function ajax_test() {
    fetch("./json_test.php")
        .then(response => {
            console.log(1);
            return response.json();
        })
        .then(json => {
            console.log(2);
        });
}

function ajax_test2() {
    fetch("./json_test2.php")
        .then(response => {
            console.log(3);
            return response.json();
        })
        .then(json => {
            console.log(4);
        });
}
```

#### コンソールの結果
```
3
4
1
2
```
sleepが入っているjson_test.phpの結果が後から帰ってくるため順番が逆になっている

### async、awaitを使用した呼び出し
```Javascript:test.html
async_ajax_test();

async function async_ajax_test(){
    const response = await fetch("./json_test.php");
    console.log(1);
    const json = await response.json();
    console.log(2);

    console.log(3);
    const response2 = await fetch("./json_test2.php");
    const json2 = await response2.json();
    console.log(4);
}
```

#### コンソールの結果
```
1
2
3
4
```
json_test.phpにsleepが入っているが、json_test.phpの結果をawaitにより待っているため
実行順序通りになっている

# エラー処理
## 非同期時
```Javascript:test.html
ajax_test();

function ajax_test() {
    fetch("./json_test.php")
        .then(response => {
            if (!response.ok) {
                // httpステータス200以外でも入ってくるので200以外ならばエラーを投げる
                console.error(`status = ${response.status}, error = ${response.statusText}`);
                throw new Error(response.statusText);
            }
            return response.json();
        })
        .then(json => {
            console.log(json);
        }).catch(error => {
            // ネットワーク通信に失敗したとき
            console.error(error);
    });
}
```
httpステータス200以外でもthenに入ってくるのでresponse.okで判定し、ネットワークエラー時はcatchで拾う

## async、awaitを使用した時
```Javascript:test.html
async_ajax_test();

async function async_ajax_test() {
    try {
        const response = await fetch("./json_test.php");
        const json = await response.json();
        console.log(json);
    } catch (err) {
        console.error(err);
    }
}
```
await使用時はtry catchで囲む

## ajax通信を途中で中止したい場合
AbortControllerを使用する

```Javascript:test.html
<button id="abort_fetch">中断</button>
中断ボタンを用意する

const controller = new AbortController();
const signal = controller.signal;

ajax_test();

function ajax_test() {
    fetch("./json_test.php", {signal: signal})
        .then(response => {
            if (!response.ok) {
                // httpステータス200以外でも入ってくるので200以外ならばエラーを投げる
                console.error(`status = ${response.status}, error = ${response.statusText}`);
            }
            return response.json();
        })
        .then(json => {
            console.log(json);
        }).catch(error => {
            if (error.name === 'AbortError') {
                console.log('中断しました。');
                return
            }

            // ネットワーク通信に失敗したとき
            console.error(error.message);
    });
}

let abort_fetch = document.getElementById('abort_fetch');
abort_fetch.addEventListener('click', function() {
    controller.abort();
});
```
#### コンソールの結果
```
中断しました。
```

非同期処理を中断できるAbortControllerのシグナルオブジェクトを生成し、
fetchの第2引数にsignalオプションを指定します。
イベントリスナーでabort()を呼び出すことでフェッチを中断することができます。

詳しい解説は下記を参考に
https://developer.mozilla.org/ja/docs/Web/API/AbortController/signal

## リクエスト時のオプション
fetch apiのデフォルトのメソッドはGETだがPOSTで送信したいときは
fecthの第2引数にオプションを指定する。

```php:post_test.php
<?php
var_dump($_POST);
?>
```

```Javascript:test.html
ajax_test();

function ajax_test() {
    let form = new FormData()
    form.append('nama', 'test')

    fetch("./post_test.php",
        {
            method: "POST",
            body: form
        }
        ).then(response => {
            return response.text();
        })
        .then(test => {
            console.log(test);
        });
}
```
#### コンソールの結果
```
array(1) {
  ["nama"]=>
  string(4) "test"
}
```

fetchメソッドの第2引数のオプションにmethodに"POST"を指定してbodyにFormDataオブジェクトを指定する

その他のオプションに関しては下記にて
https://developer.mozilla.org/ja/docs/Web/API/fetch

# まとめ
脱JQueryに向け、よく使用されるであろうajaxをFetchApiで実装する例を羅列してみました。
今回紹介したのは基本的な使い方のみでしたが、移行するきっかけになれば幸いです。
Fetchはまだまだ色々な機能がありますのでぜひとも使いこなしてください。