fetch APIとPromiseの備忘録

# 初めに
　この記事は、仕事でfetch APIやPromiseについて調べた時の備忘録になります。非同期処理やコールバック変数の説明、それらを説明するための実用的なサンプルコードは本記事では紹介しないので、ご了承ください。

## 本記事でやりたいこと
　fetch APIを使って、ローカルにあるテキストファイルの文字を読み込む。

# fetch APIとは
　ドキュメントによると、「リクエストやレスポンスといった「プロトコル」を操作する要素にアクセスするためのJavaScriptインターフェイス」とのこと。

https://developer.mozilla.org/ja/docs/Web/API/Fetch_API/Using_Fetch

　他に文献を調べてまとめたところ、ザックリ下記のような感じ
- HTTPリクエストを発行するAPIである。
- HTTPとあるが、ローカルのディレクトリパスも指定できる。
- 様々なファイル形式(txt,json,画像ファイル等々)を読み込むことが出来る。

## fetchの構文、戻り値
```
　fetch(url, [options])
  .then(response => {
    /*処理*/
  })

　//url：アクセスするURL、またはディレクトリパス
　//options：オプションのパラメータ
　//戻り値：Responseオブジェクトを結果に持つPromiseオブジェクトが返される
```
　fetchの構文と戻り値を調べていたら、thenメソッドやPromiseオブジェクトという言葉が出てきました。

### Promiseオブジェクトって？
　非同期処理の「状態」と「結果」を表すオブジェクト。生成するには、**コールバック関数を2つ受け取る関数**を引数に渡してnewする必要がある(ややこしい...)

```Promise.js
  //Promiseオブジェクトの生成方法
  let promise = new Promise(function(resolve, reject) {
    /* 処理 */
  });
  //resolve:コールバック関数。実行されると、Promiseの処理が完了したことになる。
  //reject(任意):コールバック関数。実行されると、Promiseの処理が失敗したことになる。
```

　試しにコードを書いて動かしてみます。
```promise.js
  let pendingPromise = new Promise((resolve, reject) => {
  });
  console.log(pendingPromise);

  let fulfilledPromise = new Promise((resolve, reject) => {
    resolve("処理完了");
  });
  console.log(fulfilledPromise);

  let rejectPromise = new Promise((resolve, reject) => {
    reject("処理失敗");
  });
  console.log(rejectPromise);
```

　デベロッパーツールで確認してみると、
![qiita-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2448205/cb522b4c-383a-0a3f-93d6-1d537f5bc90f.png)

　Promiseの引数のコールバック関数が実行されないと、PromiseStateはpending(待機)となります。resolveが実行されればfulfilled(完了)、rejectが実行されればrejected(失敗)とそれぞれPromiseStateが変わります。
　また、**PromiseResultプロパティの値ですが、コールバック関数(resolveとreject)の引数の値が設定される**ようです。

### thenメソッドって？
　Promiseオブジェクトが継承しているメソッドの一つ。Promiseの状態がfulfilledかrejectedの時に、**thenの引数のコールバック関数が実行される。**
```
  Promise.then(function(fulfilled) {/*処理*/}, function(rejected) {/*処理*/})
  //第一引数:PromiseStateがfulfilled(完了)の時に実行される
  //第二引数(任意):PromiseStateがrejected(失敗)の時に実行される
```
　試しにコードを書いて動かしてみます。
```then.js
    let fulfilledPromise = new Promise((resolve, reject) => {
      resolve("処理完了");
    }).then(
      function(fulfilled) {
        console.log("fulfilledPromise:" + fulfilled);
      }, 
      function(rejected) {
        console.log("rejectPromise:" + rejected);
      });

    let rejectPromise = new Promise((resolve, reject) => {
      reject("処理失敗");
    }).then(
      function(fulfilled) {
        console.log("fulfilledPromise:" + fulfilled);
      }, 
      function(rejected) {
        console.log("rejectPromise:" + rejected);
      });
```

デベロッパーツールで確認してみると、
![qiita-06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2448205/9d887dae-9049-7f25-c199-c97d3fdd1a9d.png)

　**コールバック関数の引数(fulfilledとrejected)には、PromiseResultの値を受け取ることが出来ます。** PromiseResultに値を設定するには、Promiseオブジェクトのコンストラクタに設定しているコールバック関数(resolveとreject)に引数を指定すればいいのでしたね。

## fetchを実際に実行してみた
　今までの調査の要点をまとめると、下記の流れでテキストファイルの中身を取得出来そうです。
- fetchの戻り値(Promiseオブジェクト)のPromiseResultにはResponseオブジェクトが入っている
- fetchの戻り値のthen()を呼び出して、PromiseResultの値(Responseオブジェクト)を取得
- Responseオブジェクトのtext()を呼び出して、テキストファイルの中身を取得！

　jsファイルと同じ階層に「取得成功」と記載したtxtファイルを置いて、それを読み込みます。コンソールでオブジェクトの状態をチェックしながら実行してみます。

```sample.js
  let txt = "./tmp.txt";

  let result = fetch(txt);
  console.log(result);
  result.then(response => {
    console.log(response.text());
  });
```

結果は…

![qiita-04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2448205/e6718370-12c8-a2b6-c9e4-2405bca52018.png)

見たところ、PromiseオブジェクトのPromiseResultプロパティにテキストファイルの中身が入っているようです...なんで？

### Responseクラスについて
　Responseオブジェクトのtextメソッドは、Stringではなく「レスポンスの本体のテキスト表現で解決するPromiseを返す」そうです。つまり、response.text()で取得したPromiseオブジェクトのthenメソッドを呼び出す必要がありそうです。

https://developer.mozilla.org/ja/docs/Web/API/Response

## 改めてfetchを実行

```sample.js
  let txt = "./tmp.txt";

  let result = fetch(txt);
  console.log(result); //PromiseResult:Response
  result.then(response => {
    let text = response.text();
    console.log(text); //PromiseResult:取得成功
    text.then(response => {
      console.log(response);
    });
  });
```

結果は...

![qiita-05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2448205/5a5d5a39-bd1d-8a52-f22d-8bfada1a995a.png)

　ようやくテキストファイルファイルの中身を取得することが出来ました。

# ラクな方法
　Promiseについて色々調べましたが、実はコード量が少なくて簡潔な書き方もあります。
```async.js
  let txt = "./tmp.txt";
  func1 = async function (){
    let result = await fetch(txt);
    let text = await result.text();
    console.log(text);
  }
  func1();
```
　async,awaitについては、こちらの記事で分かりやすく解説されています。

https://qiita.com/soarflat/items/1a9613e023200bbebcb3