BFT名古屋 TECH BLOG

日々の業務で得た知識を所属するエンジニアたちがアウトプットしていきます。

【Vue.js】【JavaScript】非同期処理で苦戦した話

初めに

こんにちは。株式会社BFT名古屋支店新人エンジニアのないとうです。
先日、Vue.jsでAPIの呼び出し処理を行った際に、非同期処理の部分で苦戦しました。
今回はその時にVue.jsの非同期処理について試したことを書いていきたいと思います。

環境

・Node.js : 12.22.3
・Vue.js : 4.5.13
・axios : 0.21.1

要件

・複数回APIを呼び出してその全ての処理が終了した後に次の処理に進む
f:id:bftnagoya:20211025142918p:plain

APIの呼び出し

axiosを用いた非同期通信

APIを呼び出すためにaxiosというライブラリを用いました。
これはVue.jsで一般的に使われているライブラリで、HTTPリクエストメソッドを用いて通信を行うことができます。
使用にはライブラリのインストールが必要なので、以下のコマンドでインストールします。

$ cd 【プロジェクトのパス】
$ npm install axios --save

今回はgetメソッドを用いて通信を行い、get.jsとして以下のようにプログラムを作成しました。

import axios from 'axios'

  function get(){
       var url=【APIのURL】
       //送信処理
       axios.get(
          //送信URL
          url,
          {
            headers:{
              【ヘッダー情報】
            },responseType:'arraybuffer'

          //送信成功時処理
          }).then(response =>{

             【成功時処理】 

          //例外処理
          }).catch(e=>{
             alert(e);
        });
      }

export { get }

この状態で、APIを呼び出すことが可能になりました。

非同期処理

JavaScriptでは、処理が上から順番に進んでいきます。
その中で非同期処理(今回はAPIの処理)を伴う処理があると、処理の終了を待たずに先に進んでしまいます。
f:id:bftnagoya:20211025130954p:plain
そこでAPIの処理が終了するまで、JavaScriptの処理を停止させる必要があります。

async,awaitを使った非同期処理

今回はasyncとawaitを使って非同期処理の完了まで、JavaScriptの処理を停止するようにget.jsを変更しました。

import axios from 'axios'

  async function get(){
       var url=【APIのURL】
       //送信処理
       await axios.get(
          //送信URL
          url,
          {
            headers:{
              【ヘッダー情報】
            },responseType:'arraybuffer'

          //送信成功時処理
          }).then(response =>{

             【成功時処理】 

          //例外処理
          }).catch(e=>{
             alert(e);
        });
      }

export { get }

get.jsからほとんど変わってはいませんが、3行目にasyncを,5行目にawaitを入れました。
次にVue.jsのmethods内で関数を呼び出す処理を作成します。

・・・
<script>
  import { get } from 【get.jsのパス】
・・・
  methods:{
     get_func : async function(){
         ・・・
         await get();
         ・・・
     }
・・・
</script>

このように記載することで、非同期処理を完了するまでJavaScriptが停止しました。  

複数の非同期処理

今回はAPIを複数回呼び出したいのですが、axiosでは1度の通信しか行えません。
ですので、JavaScriptを用いて複数回get.jsを呼び出す必要があります。

forEach文での非同期処理

繰り返し呼び出せば、複数回APIを呼び出せると考えたので、forEach文を用いて処理を作成しました。

<script>
  import { get } from 【get.jsのパス】
・・・
  methods:{
     get_func : async function(){
         ・・・
        const a = [1,2,3,4,5];
        a.forEach(async (value) => {
           ・・・
           await get();
           ・・・
         });
         ・・・
     }
・・・
</script>

このプログラムでは、非同期処理が完了するまで処理が停止せず処理が進んでしまいました。
調査したところforEachのMDNにasync,awaitで停止しないとコード例で示されており、forEachを使えないことがわかりました。

for文を用いた非同期処理

次はfor文を用いた処理を作成しました。

<script>
  import { get } from 【get.jsのパス】
・・・
  methods:{
     get_func : async function(){
         ・・・
        async for(var i=0; i<5; i++){
           ・・・
           await get();
           ・・・
         }
         ・・・
     }
・・・
</script>

このプログラムでは、非同期処理の完了まで処理を停止させることに成功しました。
しかしfor文での非同期処理は、1つのAPIの処理が終了したら次のAPIを呼ぶような順序で処理が進み、処理が完了するのに時間がかかってしまいました。
f:id:bftnagoya:20211025154110p:plain

Promise.allを用いた非同期通信

非同期処理を並列実行する方法を調査したところ、Promise.allというものがありました。
Promise.allは並列実行したい処理を配列に挿入しそれを引数として実行することで、配列内の処理がすべて終了するまで処理を停止する関数です。
【for文を用いた非同期処理】と違い配列内の処理は並列実行されるので処理にかかる時間を短縮することができます。
f:id:bftnagoya:20211025174613p:plain
こちらを用いて、以下のようにプログラムを作成しました。

<script>
  import { get } from 【get.jsのパス】
・・・
  methods:{
     get_func : async function(){
         ・・・
        promise_ary=[];
        for(var i=0; i<5; i++){
  
           var promise = get();
           promise_ary.push(promise);
           
         }

        Promise.all(promise_ary).then((result)=>{
          ・・・
        });
     }
・・・
</script>

このプログラムで非同期処理の並列実行が行えました。 ただし、APIでの処理が終了する順番はバラバラなのでそこには注意する必要があります。
もしAPIの処理を開始した順番と終了した順番を同じにしたい場合は【for文を用いた非同期処理】を用いる必要があります。

終わりに

今回はPromise.allを用いることで、要件にあった処理にすることができました。
非同期処理を使いこなせるようにこれからも学習していきたいと思います。
それでは。


qiita.com

developer.mozilla.org

blog.narumium.net

developer.mozilla.org