よく見るけどよくわからないasync/await

# はじめに


# 非同期処理とは？
[非同期処理ってどういうこと？JavaScriptで一から学ぶ https://qiita.com/kiyodori/items/da434d169755cbb20447](https://qiita.com/kiyodori/items/da434d169755cbb20447)

# Callback関数とCallback地獄
- Callback 関数：非同期な処理が完了したら実行する関数
- いろいろなところで使用される
    - イベントリスナ（クリックされたら〇〇を実行）
    - ファイル読み込み（ファイルを読み込んだら〇〇を実行）
    - Ajax 通信（通信が終わったら〇〇を実行）
    - などなど
- 問題点：シンプルな処理であれば問題ないが、Callback のネストが始まると途端に辛くなる

## 課題1：Callbackのネストを体感する(15～25分)
- 目的：連続した非同期処理を行いたい状況で Callback を使用すると、Callback がネストし可読性が低くなることを体感する。
- 内容：以下の 1～3 を実現する。
- 1. DynamoDB からユーザーレコードを取得する。

    ```javascript:これをLambdaに貼り付けてください
    const AWS = require('aws-sdk');
    const documentClient = new AWS.DynamoDB.DocumentClient({region: 'ap-northeast-2'});

    exports.handler = (event) => {
        console.log("[START]");
        const param1 = {
            TableName: 'async-lecture-users',
            Key: {
                userId: 'U0001',  
            },
        };
        documentClient.get(param1, (err, data) => {
            if (err) {
                console.error(err);
                return;
            }
            console.log(data);
        });
        console.log("[END]");
    };
    ```
- 2. レコード取得処理を追加する。
    - 内容：ユーザーレコードのグループ ID をもとに、グループレコードを取得する。
    - ポイント：1.で取得したグループ ID もとに、グループレコードを取得する→documentClient.get がネストするはず！
    - 条件：

    ```javascript
    {
        TableName: 'async-lecture-groups',
        Key: {
            groupId: data.Item.groupId, // 1.で取得したユーザーレコードのグループID
        },
    }
    ```
- 3. さらにレコード取得処理を追加する。
    - 内容：グループレコードの平社員 ID をもとに、ユーザーレコードを取得する。
    - 条件：

    ```javascript
    {
        TableName: 'async-lecture-users',
        Key: {
            userId: data.Item.hiraShainId, // 2.で取得したグループレコードの平社員ID
        },
    }
    ```

## 解答例

```javascript
    const AWS = require('aws-sdk');
    const documentClient = new AWS.DynamoDB.DocumentClient({
      region: 'ap-northeast-2',
    });

    exports.handler = (event) => {
      console.log('[START]');
      const param1 = {
        TableName: 'async-lecture-users',
        Key: {
          userId: 'U0001',
        },
      };
      documentClient.get(param1, (err, data) => {
        if (err) {
          console.error(err);
          return;
        }
        console.log(data);

        const param2 = {
          TableName: 'async-lecture-groups',
          Key: {
            groupId: data.Item.groupId, // 1.で取得したユーザーレコードのグループID
          },
        };
        documentClient.get(param2, (err, data) => {
          if (err) {
            console.error(err);
            return;
          }
          console.log(data);

          const param3 = {
            TableName: 'async-lecture-users',
            Key: {
              userId: data.Item.hiraShainId, // 2.で取得したグループレコードの平社員ID
            },
          };
          documentClient.get(param3, (err, data) => {
            if (err) {
              console.error(err);
              return;
            }
            console.log(data);
          });
        });
      });
      console.log('[END]');
    };
```

# Promiseの登場
[Promise再入門① ~Promise基本編~ https://qiita.com/tfrcm/items/1dfe4265c36bea903ab3](https://qiita.com/tfrcm/items/1dfe4265c36bea903ab3)
[Promiseについて0から勉強してみた https://qiita.com/toshihirock/items/e49b66f8685a8510bd76](https://qiita.com/toshihirock/items/e49b66f8685a8510bd76)

## 課題2：CallbackのネストをPromiseで解消する(10~20分)
- 目的：Promise を使うと、Callback のネストを解消できることを確認する。
- 内容：課題 1.1～1.3 の内容を Promise を使って記述する。

## 解答例

```javascript
    const AWS = require('aws-sdk');
    const documentClient = new AWS.DynamoDB.DocumentClient({
      region: 'ap-northeast-2',
    });

    exports.handler = (event) => {
      console.log('[START]');
      const param1 = {
        TableName: 'async-lecture-users',
        Key: {
          userId: 'U0001',
        },
      };

      documentClient.get(param1).promise()
          .then((data) => {
            console.log(data);
            
            const param = {
                TableName: 'async-lecture-groups',
                Key: {
                    groupId: data.Item.groupId,
                },
            };
            
            // thenブロックでPromiseをリターンすることで、次のthenの引数にデータを渡せる
            return documentClient.get(param).promise();
          })
          .then((data) => {
            console.log(data);
            
            const param = {
                TableName: 'async-lecture-users',
                Key: {
                    userId: data.Item.hiraShainId,
                },
            };
            
            return documentClient.get(param).promise();  
          })
          .then((data) => {
            console.log(data);
          })
          .catch((err) => {
            console.error(err);
          });
      console.log('[END]');
    };
```

# async/awaitの時代
[async await の使い方 https://qiita.com/niusounds/items/37c1f9b021b62194e077](https://qiita.com/niusounds/items/37c1f9b021b62194e077)

## 課題3：async/awaitで書く(10~20分)
- 目的：async/await を使うと簡潔に非同期処理を記述できることを確認する。
- 内容：課題 1.1～1.3 の内容を async/await を使って記述する。

## 解答例
```javascript
    const AWS = require('aws-sdk');
    const documentClient = new AWS.DynamoDB.DocumentClient();
    
    exports.handler = (event) => {
      console.log('[START]');
      const param1 = {
        TableName: 'async-lecture-users',
        Key: {
          userId: 'U0001',
        },
      };
    
      documentClient.get(param1).promise()
          .then((data) => {
            console.log(data);
    
            const param = {
                TableName: 'async-lecture-groups',
                Key: {
                    groupId: data.Item.groupId,
                },
            };
    
            // thenブロックでPromiseをリターンすることで、次のthenの引数にデータを渡せる
            return documentClient.get(param).promise();
          })
          .then((data) => {
            console.log(data);
    
            const param = {
                TableName: 'async-lecture-users',
                Key: {
                    userId: data.Item.hiraShainId,
                },
            };
    
            return documentClient.get(param).promise();  
          })
          .then((data) => {
            console.log(data);
            console.log('[END]');
          })
          .catch((err) => {
            console.error(err);
          });
    };
```