Nuxtを使ってPromise, async/awaitのコードを書く

## 動機

- JSはほぼ初心者。
- Nuxt, Firebaseを使うことになった
- [【v2対応】Nuxt.jsとFirebaseを組み合わせて爆速でWebアプリケーションを構築する](https://qiita.com/potato4d/items/cfddeb8732fec63cb29c)を読んだ
- しかし[コード内](https://github.com/potato4d/nuxt-firebase-sns-example/blob/master/app/pages/index.vue)の`auth`周りの処理や`Promise`, `async/await`の処理がどう行われているかよくわからなかった
- [Promiseの本](https://azu.github.io/promises-book/#_async_function%E3%81%A8%E9%85%8D%E5%88%97)の中に両方を用いたサンプルコードがあったので、それをNuxtで使うことができるように移植する

なお、サンプルコードは上のリンクのコードを用いる(下に転載)が、少し機能を変えて、
1. `input`タグ内の文字列を`,`区切りでリスト化する
2. `hoge`という文字列から始まっていればその文字列を、それ以外は`fuga`という文字列を結果に格納
3. 結果を１つずつ表示する

という風にしている。

```javascript:fetchResources.js
function dummyFetch(path) {
    return new Promise(function(resolve, reject){
        setTimeout(function(){
            if (path.startsWith("/resource")) {
                resolve({ body: `Response body of ${path}` });
            } else {
                reject(new Error("NOT FOUND"));
            }
        }, 1000 * Math.random());
    });
}

// 複数のリソースを取得しレスポンスボディの配列を返す
async function fetchResources(resources) {
    // リソースをまとめて取得する
    const promises = resources.map(function(resource){
        return dummyFetch(resource);
    });
    // すべてのリソースが取得できるまで待つ
    // Promise.allは [ResponseA, ResponseB] のように結果が配列となる
    const responses = await Promise.all(promises);
    // 取得した結果からレスポンスのボディだけを取り出す
    return responses.map(function(response){
        return response.body;
    });
}
const resources = ["/resource/A", "/resource/B"];
// リソースを取得して出力する
fetchResources(resources).then(function(results){
    console.log(results); // => ["Response body of /resource/A", "Response body of /resource/B"]
});
```

## １ファイル内で完結させる実装
まずはvuexの`Store`機能を使わず、`dummy.vue`ファイル内のみで完結させる

```vue:pages/dummy.vue
<template>
  <div>
    <!-- 送信用 -->
    <div>
      <input v-model="resources" type="text">
      <button @click="submit">
        送信
      </button>
    </div>
    <!-- 表示用 -->
    <div>
      <ul>
        <li v-for="(result, index) in results" :key="index">
          {{ result }}
        </li>
      </ul>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      resources: '',
      results: []
    }
  },
  methods: {
    async submit() {
      const resources = this.resources.split(',')
      const promises = resources.map((resource) => {
        return this.dummyFetch(resource)
      })
      const responses = await Promise.all(promises)
      return responses.map((response) => {
        this.results.push(response.body)
      })
    },
    dummyFetch(resource) {
      return new Promise((resolve) => {
        setTimeout(() => {
          if (resource.startsWith('hoge')) {
            resolve({ body: resource })
          } else {
            resolve({ body: 'fuga' })
          }
        }, 1000 * Math.random())
      })
    }
  }
}
</script>
```

挙動はこんな感じ
わかりにくいですが、上の文字列が自分で打った文字列(入力)、下のリストが結果です。
<img width="251" alt="スクリーンショット 2019-05-29 15.09.51.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/190157/9019bbb4-424b-2bae-12e6-e82399c86a15.png">


## Store機能を使って実装する
[NuxtにおけるStore](https://ja.nuxtjs.org/guide/vuex-store/)は、２つの書き方があります、

> ・モジュールモード: store ディレクトリ内のすべての *.js ファイルが 名前空間付きモジュール に変換されます（index はルートモジュールとして存在します）
・クラシックモード(廃止予定): store/index.js がストアインスタンスを返します

(上のリンクより)

クラシックモードで書かれているコードが多いと思いますが、廃止予定とあったので今回は**モジュールモードを使ってStore機能を使用します。**
また、vueファイル内の`<template>`は全く同じなので割愛します

```vue:dummy.vue
<script>
import { mapActions, mapState } from 'vuex'

export default {
  data() {
    return {
      resources: ''
    }
  },
  computed: {
    ...mapState('dummy', ['results'])
  },
  methods: {
    // `this.fetch()` を `this.$store.dispatch('dummy/fetch')` にマッピング
    ...mapActions('dummy', ['fetch']),
    submit() {
      this.fetch(this.resources)
    }
  }
}
</script>
```

```javascript:store/dummy.js
export const state = () => ({
  results: []
})

export const mutations = {
  fetchResources(state, results) {
    // state.results.push(response.body)
    state.results = results
  }
}

function dummyFetch(resource) {
  return new Promise((resolve) => {
    setTimeout(() => {
      if (resource.startsWith('hoge')) {
        resolve({ body: resource })
      } else {
        resolve({ body: 'fuga' })
      }
    }, 1000 * Math.random())
  })
}

async function fetchResources(resources) {
  const promises = resources.split(',').map((resource) => {
    return dummyFetch(resource)
  })
  const responses = await Promise.all(promises)
  return responses.map((response) => {
    return response.body
  })
}

export const actions = {
  fetch({ commit }, resources) {
    fetchResources(resources).then((results) => {
      commit('fetchResources', results)
    })
  }
}
```

store内の`results`に対して、action, mutationを用いて結果を格納し、それを描画しています。

### 最後に
`dummyFetch`, `fetchResources`関数はどこに置けばよいのかがわからなかった。
一旦は呼び出しができるようにファイル内にかきましたが、`plugins`ディレクトリ内に`utils.js`などをおいて書いていけばいいのか、そのほかに方法があるのか...
わかる方、教えていただけますと幸いです。