GeoFresher
GeoFresher

Reputation: 301

Synchronize API calls in a for loops VueJS

I am trying to get synchronized flow inside a for loop which each loop having to call a API. The flow is summarized as follows:

  1. A Demo1() function containing forloop executes one by one, however in each loop it does a API call.,
  2. A MainFunction() retrieves after the for loop has executed and does the final API call.

Supporting API calls for the same function is shown in code and seems quite self explanatory

The code structure is as follows:


</script>
...

    async MainFunction() {
          
          if (dataPresent) {
            let clientFieldDetails = await this.Demo1()
              .then(() => {
                //This does the final API call based on the results fetched from for loop  
                this.processFinalAPICall(); 
              })
              .catch(err => {
                console.log("Something went wrong... ", err);
              });
          } else {
            console.log(
              "No data.."
            );
          }
        },
    
        async Demo1() {
          //Traversing around each fieldInfo
          //this.dataPresent.items.forEach(item => {
          //Replacing with normal for loop
           for(item of this.dataPresent.items){
            if (item.model) {
              //Upload item model API Call
              this.uploadItem(item.model)
                .then(response => {
                  //PUT API Call
                  this.putItemModel().then(response => {
                    var result = response.data;
                    //Add itemModel fetched from API response
                    models.push(result);
                    console.log(result)
                  });
                })
                .catch(err => console.log("Axios err: ", err));
            } else {
              //Inside item price details
              console.log("inside item price");
              //API call for fetching price info
              this.getitemPriceInfo(item.id);
            }
          });
        },
    
        getitemPriceInfo(itemid){
            if(itemid){
                //API call for fetching price info
                this.getPriceinEuro(itemid);
                itemsPrice.push(result)
            }
            else{
                this.getPriceWorldWide().then(response => {
                   if(response.data === "item not created") 
                     //Create new item API call
                     this.createNewItem(item.id)
                   else{  
                    var result = response.data;
                    //Fetched  API response for itemsPrice
                    itemsPrice.push(result);
                    console.log(result);
                    //Update item API call
                    this.updatePriceItem(item.id);
                   }
                  });
            }
        },    

  //EDIT: Adding API call

  async getPriceinEuro(itemId) {
      await this.$axios
        .get("/auth/getEuroPrice", {
          params: {
            itemID: itemId
          }
        })
        .then(response => {
          console.log(" Resp :" + response.data);
          let result = response.data;
          //This gives me the price
         itemsPrice.push(result)
        });
    },
       
    
        processFinalAPICall(){
            //get itemsPrice and models price pushed
            var apiBodyModel = []; 
            this.models.forEach(model=>{
               var uri = {
                   url: /modelInfo/+model
               }
              apiBodyModel.push(uri)  
            })
    
            var apiBodyPrice = []; 
            this.itemsPrice.forEach(price=>{
               var uri = {
                   url: /priceInfo/+price
               }
              apiBodyPrice.push(uri)  
            })
            //Create a post body request from above data and POST
            ....
        }
 ...
</script>

The code currently loops in for loop and doesnt wait for the API calls to finish. It executes processFinalCall() first and then the API calls. I am not sure about async/await, if I used it wrong please excuse. How do i get the the forLoop executed first and then the initiating the processFinalAPICall() from MainFunction?

Please let me know if I am doing it the right way. Thanks :)

I am using Node version 8.11 due to our project dependencies.

EDITED: Added API function Call for reference

Upvotes: 2

Views: 2072

Answers (2)

NMSD
NMSD

Reputation: 494

I guess its a simple change over from what @marsnebulasoup added in his mockup solution. From your comments I tried to replace upload method with axios call. You are missing return keyword after the function call , i.e,

upload(item) {
  console.log("Iten value:"+ item);
  return axios.get("https://jsonplaceholder.typicode.com/posts/" +item)
.then(response => {
  console.log("Done processing API call (Times:"+ item)
  console.log(response.data);
})
.catch(console.log);

A simple code changeover is designed based on previous answer by @marsnebulasoup in Replit:

EDIT: Added correct reference:

Code Reference: https://replit.com/join/comkahdm-gagangowda89

Cheers.

Upvotes: 1

marsnebulasoup
marsnebulasoup

Reputation: 2660

I'm fairly sure that the problem you have lies in your Demo1 function, which, very broadly, looks like this:

async Demo1() {
  [ARRAY OF ITEMS].forEach(item => {
    this.uploadItem(item)
      .then(response => {
        // do some stuff
      });
    .catch(err => /* log errors */);
  });
}

You don't await the upload here, so when you call Demo1() in MainFunction(), it'll go through the uploads without waiting for the previous one to finish first. I think the easiest way to get around this would be to use a for-of loop instead, since you pass a function to .forEach, and that just complicates things.

So instead of [ARRAY OF ITEMS].forEach(item => { ..., you can do this:

async Demo1() {
  for(let item of [ARRAY OF ITEMS]) {
    await this.uploadItem(item);
  }
}

And your modified Demo1 function would look like this:

async Demo1() {
  //Traversing around each fieldInfo
  for (let item of this.dataPresent.items) {
    if (item.model) {
      //Upload item model API Call
      await this.uploadItem(item.model)
      //PUT API Call
      let response = await this.putItemModel();
      var result = response.data;
      //Add itemModel fetched from API response
      models.push(result);
      console.log(result)
    } else {
      //Inside item price details
      console.log("inside item price");
      //API call for fetching price info
      this.getitemPriceInfo(item.id);
    }
  };
}

Note that I haven't tested this, because I don't have the full code to plug it into, so I can't fully guarantee that it'll work. If it doesn't, let me know, so I can help fix it

Here's a bad mockup of this solution.

Upvotes: 2

Related Questions