0

Im trying to fetch some data in dependecy of currently existing data. The usecase is the following: I have a json array of groups, to calculate the amount of all transactions of each group i have to do an axios.get request for each group (to request this groups i need there groupIds, existing in the groups array). But i think i stuck cause i dont really know how to iterate through a for loop asynchronously. Here is what i did:

repareTransactionAmouts: function(){
     for(var i = 0; i < this.transactionGroups.length; i++){
         var groupId = this.transactionGroups[i].groupId
         this.transactionsGroupsCount = i;
       Promise.all([this.calculateTransactionAmounts(groupId)]).then( promiseData =>  {

    this.transactionGroups[this.transactionsGroupsCount].totalAmount=promiseData[0]

     if(this.transactionsGroupsCount == this.transactionGroups.length){
       this.transactionGroups.sort(this.GetSortOrder("totalAmount"))
       this.amountsCalculated = true;
     }
    }
 }
 },

transactionsGroups is my array of filtered groups with transactions and transactionsGroupCount is a global variable to add the transactionamounts to the array position on [transactionsGroupCount]. When all groups are filled with the amout i want to sort this and set a boolean.

Next the function calculateTransactionAmounts:

    calculateTransactionAmounts: function(groupId){
return new Promise((resolve, reject) => {
  var transactions = []
  var amount = null
      axios
        .get(webServiceURL + "/groups/" + groupId, {
          headers: { Authorization: "0 " + this.authToken }
        })
        .then(response => {
            transactions = response.data.payload.transactions;


console.log("Desired Group: " + JSON.stringify(response.data.payload));
                for(let j = 0; j < transactions.length; j++){
                  amount += transactions[j].amount
                  console.log("Transactiongroup" )                                   
                  console.log(JSON.stringify
                  (this.transactionGroups[this.transactionsGroupsCount]))                                             
              resolve(amount)
            }              
        })
        .catch(e => {
          console.log("Errors get groupids: " + e);
          reject(e)
        });     
      })},

The main problem here is, that the for-loop is processed completly before the function calculateTransactionAmounts is called, so i have some calls but all with the same groupId. There is some fancy stuff happening which i cant explain why: The output "Desired Group" displays me every group i have in my array, but the "this.transactionGroups[this.transactionsGroupsCount]" outputs me allways the same group, for every iteration.

If it helps: im developing a vue2 app and need this fetched amount data to display some transaction charts

5
  • 1
    by the way, you do Promise.all([this.calculateTransactionAmounts(groupId)]).then - so, you're running Promise.all on a single promise .. just do this.calculateTransactionAmounts(groupId).then instead Commented Jan 17, 2018 at 23:20
  • 1
    Also, avoid the explicit Promise construction anti-pattern - which you are guilty of in calculateTransactionAmounts function as axios.get returns a Promise, there's no need to wrap that Promise in a new Promise Commented Jan 17, 2018 at 23:22
  • 1
    by the way, I believe your code boils down to jsfiddle.net/zxk59o6c Commented Jan 17, 2018 at 23:44
  • @JaromandaX I just copy pasted ur snipped and all i tried within 8 hours now is resolved. Ur my personal genious :* Thank you so much! Commented Jan 18, 2018 at 0:15
  • I've added an answer, with some explanation of the changes to your code. Commented Jan 18, 2018 at 0:25

1 Answer 1

1

Analysing your code, it can be greatly simplified as follows

prepareTransactionAmouts() {
    return Promise.all(this.transactionGroups.map((group, i) => 
        this.calculateTransactionAmounts(group.groupId)
        .then(promiseData => group.totalAmount = promiseData)
    )).then(results => {
        this.transactionGroups.sort(this.GetSortOrder("totalAmount"));
        this.amountsCalculated = true;
    });
},
calculateTransactionAmounts(groupId) {
    return axios.get(webServiceURL + "/groups/" + groupId, {
        headers: {
            Authorization: "0 " + this.authToken
        }
    })
    .then(response => 
            response.data.payload.transactions.reduce((total, { amount }) => total + amount, 0)
    );
}

Changes from your code include

  1. Using Promise.all on promises returned by mapping this.transactionGroups to the (Promise) result of each call to this.calculateTransactionAmounts

  2. Performing the this.transactionGroups.sort and amountsCalculated = true once all the above promises have resolved - rather than tracking the index, since this does not account for asynchronism anyway

  3. Removing the new Promsie anti pattern in calculateTransactionAmounts

  4. Simplifying the amount += transactions[j].amount by using Array#reduce

  5. In general, using modern (ES2015+) javascript where applicable

Sign up to request clarification or add additional context in comments.

1 Comment

thank you so much also for explaining. I must say im pretty new to Javascript, have to do this for a study project but trying to improve further :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.