async, await入門

# はじめに
この記事は、社内勉強会の発表用として作成したものを、一部加工して公開しているものです。
間違っていることもあると思いますが、コメントで指摘していただけると幸いです。

---

# Promiseのおさらい
* 非同期関数を扱うためのインターフェース

```javascript
new Promise((resolve, reject) => {
    //非同期処理
    hoge.readFile(file, function(err, data){
      if (err) {
        reject(err); // errがあればrejectを呼び出す
        return;
      }

      resolve(data); // errがなければ成功とみなしresolveを呼び出す
    });
});
```
* resolveは成功時に呼ぶ関数
* rejectは失敗時に呼ぶ関数

---

## Promiseってどういう風に使うの？

```javascript
axios.get("https://hoge.fuga.com")
    .then(response => console.log(response.status)) //成功時の処理
    .catch(error => console.log(error.response.status))  //失敗時の処理
```

---

## Promiseがつらいときってどんな時？
例えば…

非同期関数の結果を次の非同期関数で使いたいとき
`then`のネストが増えていって辛い

```javascript
asyncFunction1()  
    .then(value1 => {  
        return asyncFunction2(value1)  
            .then(value2 => {  
            return asyncFunction3(value1, value2)
                .then(value3 => {
                console.log(value3)
            })
        })  
    });
```
---

# async,awaitとは
そういったPromiseの辛いところを簡潔に書ける(全てが全て書けるわけではない。)

また、雑に言うとasync,awaitはPromiseの処理のシンタックスシュガーなので、Promiseでできないことはできない。

---
# asyncとは
非同期関数を定義する関数宣言のこと。
function や アロー関数に async を付けると「async 関数」を定義できます。

## async 関数ってなにするの？
呼び出されるとPromiseを返す
⇒`return`した場合その値が`resolve`されたものとされる。
⇒`throw`した場合その値が`reject`されたものとされる。

あまり意味はないが、asyncだけ使用してawaitは使用しなくても大丈夫。

---

# awaitとは
`async関数`内でPromiseの結果（resolve、reject）が返されるまで待機する（処理を一時停止する）演算子のこと。

```javascript
async function sample() {
    //値が返ってくるまで待機
    const result = await samplePromise();

    console.log(result);
}

//Promiseで書くと…
function sample2(){
    return samplePromise()
        .then(result => {
        console.log(result);
    })
}
```
---

# async,awaitの使用例
まずは簡単なものから

```javascript
const hoge = () => Promise.resolve(1)
const fuga = () => Promise.resolve(2)

const main = () => {
    hoge().then(x => {
        fuga().then(y => {
            console.log(x + y)
        })
    })
}
main()
```
↓

```javascript
const hoge = async () => 1
const fuga = async () => 2

const main = async () => {
    const x = await hoge()
    const y = await fuga()
    console.log(x + y)
}
main()
```

---
## 並列の非同期処理
### Promise版
```javascript
const hoge = value => {
  return new Promise(resolve => {
        setTimeout(() => {
            resolve(value * 2);
        }, 1000);
    })
}

const fuga = value => {
  return new Promise(resolve => {
        setTimeout(() => {
            resolve(value * 3);
        }, 500);
    })
}

const promiseAllSample = () => {
    const promise1 = hoge(5);
    const promise2 = hoge(10);
    const promise3 = promise2.then(value => {
        return fuga(value);
    });

    return Promise.all([promise1, promise2, promise3]);
}

promiseAllSample().then(([a, b, c]) => {
    console.log(a, b, c); // => 10 20 60
});
```
---
### async,await版
```javascript
const hoge = value => {
  return new Promise(resolve => {
        setTimeout(() => {
            resolve(value * 2);
        }, 1000);
    })
}

const fuga = value => {
  return new Promise(resolve => {
        setTimeout(() => {
            resolve(value * 3);
        }, 500);
    })
}

const promiseAllSample = async () => {
    const [a, b] = await Promise.all([hoge(5), hoge(10)]);
    const c = await fuga(b);

    return [a, b, c];
}

promiseAllSample().then(([a, b, c]) => {
    console.log(a, b, c); // => 10 20 60
});
```
---
`Array.map()`の利用も出来る。

```javascript
const hoge = value => {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve(value * 2);
        }, 1000);
    })
}

const promiseMapsample = async () => {
    const values =[5, 10, 15];
    return await Promise.all(
        values.map(async value => await hoge(value))
    );
}

promiseMapsample().then(([a, b, c]) => {
    console.log(a, b, c); // => 10 20 30
});
```
---
## エラーハンドリング
async,awaitはPromiseのシンタックスシュガーなので、`catch`をそのまま使える。

```javascript
const errorHandling= async () => {
    const result = await sample()
    console.log(result) // エラー時は到達しない
}

errorHandling()
    .catch(console.log)
```

---
# おまけ
* axiosとかでよく使う書き方。いちいち`response.data`と書くのがめんどくさいときに

```javascript
const { data } = await axios.get("https://hoge.fuga.com")
```

* awaitにしないほうが綺麗なとき。

```javascript
const x1 = await func()
const x2 = await filter1(x1)
const x3 = await filter2(x2)

// ↓ ↓ ↓

const x = await func().then(filter1).then(filter2)
```
---

# 参考
[Promise - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise)
[Promiseを使う - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Using_promises)
[async function - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/async_function)
[await - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/await)
[Promise と async/await の理解度をもう1段階上げる - Qiita](https://qiita.com/SotaSuzuki/items/f23199e864cba47455ce)
[async/await 入門（JavaScript） - Qiita](https://qiita.com/soarflat/items/1a9613e023200bbebcb3)
[async関数においてtry/catchではなくawait/catchパターンを活用する - Qiita](https://qiita.com/akameco/items/cc73afcdb5ac5d0774bc)