初学者が初学者に教える【Promise,async/await】

初学者がjavascriptの学習で一番の壁となる非同期通信。
君たちの気持ちは痛いほどわかる、、、
私も、理解に苦しんだからだ！

そんな君たちに、伝わるよう、わかりやすくこの記事を書いていこうと思う。

<h2>１：なぜpromiseが必要なのか</h2>
A:コールバック地獄を防ぐため

```javascript
console.log(1)
//setTimeout(処理内容,実行タイミング)
setTimeout(() => console.log(2), 1000)
//同じ意味
//setTimeout(function(){console.log(2)}, 1000)
console.log(3)
```

例えば、このようなコードがあります。(<a href="https://qiita.com/may88seiji/items/4a49c7c78b55d75d693b">アロー関数</a>がわからなければ）この記事を見てね。

このプログラムを実行すると、

①1
②3
③2

と出力されます。

これを

一秒待つ
1
一秒待つ
2
一秒待つ
3

と出力させるには

```javascript
setTimeout(() => {
   console.log(1)
    setTimeout(() => {
        console.log(2)
        setTimeout(() => {
            console.log(3)
        }, 1000)
    }, 1000)
}, 1000)
```

となり、ネストが深くなりますよね。これだと読みずらい！という記事がよくあると思うのですが、この例だとわりと想像しずらいですよね。setTimeoutを使っているのは、時間をかかる処理を代わりに、

１秒待ちますよ～

という関数を使って、仮に時間がかかったようにしているのです。実際はファイルを読み込むときなどの処理に時間がかかるのです。

ちなみにこれでいいのでは

```javascript
setTimeout(() => console.log(1), 1000)
setTimeout(() => console.log(2), 1000)
setTimeout(() => console.log(3), 1000)
```
と思う方いるかもしれませんが、実行すると、１秒後に、一斉に１２３と出てきます。

<h2>Promiseで読みづらさ解消</h2>

promiseの例

```javascript
//Promiseインスタンスの作成
const promise = new Promise((resolve, reject) => resolve()); 
//Promiseが終了したら「終了」と表示
promise.then(() => console.log('終了')); 
```

処理が済んだら、resolve関数を呼び出すことで終了。今回はrejectは使用していないので、省略してもよいです。


```javascript
const promise = new Promise(function (resolve) {resolve()} ); 
promise.then(() => console.log('終了')); 
```

これでも同じ意味になります。


実際の動きを見ていきましょう

```javascript
const sleep = new Promise((resolve, reject) => {
    setTimeout(() => { 
        console.log('1');
        resolve();
    }, 1000);
});

sleep.then(() => console.log('2'));

```

これで一秒立った後に１、それが完了した後に２が表示されます。

実際にさっき書いたコードをPromiseを使い書き直してみましょう

```javascript
function sleep() {
    return new Promise(function(resolve) { 
        setTimeout(function() { 
            resolve() 
        }, 1000)
    })
} 

sleep(1000)
.then(function() {
    console.log(1)
    return sleep()
}).then(function() {
    console.log(2)
    return sleep()
}).then(function() {
    console.log(3)
})
```

ネストしなくなりましたね！！！
流れとしては、

１：sleep関数実行
２：promise作成（待っててねという状態になる）
３：setTimeout関数実行
４：1秒待ってから、resolve()
５：解決したよ
６：thenへ…


アロー関数を使った同じ動作をする書き方も書いておきます
アロー関数が正しく理解できていれば、わかるはず！！！


```javascript
const sleep = ms => new Promise(resolve => setTimeout(() =>resolve(), ms))

sleep(1000)
.then( () => {
  console.log(1)
  return sleep(1000)
}).then(() => {
  console.log(2)
  return sleep(1000)
}).then(() => {
  console.log(3)
})
```

```javascript
const sleep= ms => new Promise(resolve => setTimeout(() =>resolve(), ms))

sleep(1000)
.then(() => console.log(1))
.then(() => sleep(1000))
.then(() => console.log(2))
.then(() => sleep(1000))
.then(() => console.log(3))
```

<h4>fetch<h4>

実務ではサーバーと通信するのにfetch関数をよく使います。
いちどfetchの中身を見てみましょう

```javascript
const url = "https://jsonplaceholder.typicode.com/users";
const p = fetch(url);
console.log(p);
```
なんとpromiseが返ってきていますね！
サーバーとの通信は時間がかかるので、fetchはpromiseを返し、サーバがヘッダを応答するとすぐに組み込みの Response クラスのオブジェクトで resolve します。

```javascript
fetch("https://jsonplaceholder.typicode.com/users")
  .then(res => {
    console.log(res);
    return res.json();
  })
  .then(data => {
    console.log(data);
  })
```
データの中身を扱いたい場合、このように書くのが一般的です。
流れとしては

１：promise帰ってくる
２：まつ
３：resolveで解決
４：thenへ。。。

という感じです

余談ですが、fetch(url)と

````javascript
var xhr= new XMLHttpRequest();
xhr.open("GET","URL");
xhr.send();
```
は全く同じ処理をします。





<h3>async/awaitでさらに読みやすく</h3>
thenを使わなくたって、async/awaitを使えば、非同期処理が書けます。

```javascript
function sleep(ms) {
    return new Promise(function(resolve) {
        setTimeout(resolve, ms)
    })
}

async function asyncFunc() {
    await sleep(1000)
    console.log(1)
    await sleep(1000)
    console.log(2)
    await sleep(1000)
    console.log(3)
}

asyncFunc()
```

fetch()を使った時もasync/awaitで書くと

```javascript
const USERS_API = "https://jsonplaceholder.typicode.com/users";

async function callApi() {
  const res = await fetch(USERS_API);
  const data = await res.json();
  console.log(data);
}
```

という風に書けます。

awaitを書くことで、Promiseの終了を待つことができます。

もしこのように書いてしまうと、エラーになります。

```javascript
const USERS_API = "https://jsonplaceholder.typicode.com/users";

function callApi() {
  const res = fetch(USERS_API);
  const data = res.json();
  console.log(data);
}
```

サーバー通信が終了していない間に、次の処理に進んでしまうからです。

なので、fetchを使うときは

promise

```javascript
fetch("https://jsonplaceholder.typicode.com/users")
  .then(res => {
    console.log(res);
    return res.json();
  })
  .then(data => {
    console.log(data);
  })
```

async/await

```javascript
const USERS_API = "https://jsonplaceholder.typicode.com/users";

async function callApi() {
  const res = await fetch(USERS_API);
  const data = await res.json();
  console.log(data)
```

のように書きましょう！