0

I have a function where I form the current sum of elements. Getcoin is the method in my Api, and it works correctly if I console.log each element during the foreach cycle. But as the result I got nothing in the return and console.log function

getCurrentCost() {
        let currentCostArr = [];
        let sum = 0;
    
        let existingEntries = JSON.parse(localStorage.getItem("walletData"));
        if (existingEntries == null) existingEntries = [];
    
        existingEntries.forEach(el => {
          this.coincapService
            .getCoin(el.id)
            .then((element) => {
              currentCostArr.push(element.priceUsd * el.amount)
            })
        });
    
        for (let i = 0; i < currentCostArr.length; i++) {
          sum += +currentCostArr[i];
        }
        console.log('cevf c ' + sum)
        console.log('current cost ' + currentCostArr)
    
        return currentCostArr;
      }

getCoin method

 getCoin = async (id) => {
    const coin = await this.getResource(`/assets/${id}`);
    return this._transformCoin(coin);
  }
roninbony
  • 25
  • 4
  • 1
    You need to research about the difference between synchronous and asynchronous code in Javascript. You treat `getCurrentCost` as if it's synchronous, however `this.coincapService.getCoin(el.id)` is asynchronous, and as a results its execution gets deferred until the rest of `getCurrentCost` has run. The fix in this specific case will depend on how you're trying to use this function – Jayce444 Apr 03 '22 at 00:11
  • I am trying to get the sum of the elements in my LocaleStorage via server to find out the newest price, and then, give the sum to the render() to display it – roninbony Apr 03 '22 at 00:21

2 Answers2

1

The problem is that you are not handling correctly the Promise that .getCoin() returns inside the .forEach() 'loop'. It's making multiple calls to getCoin but the code outside the forEach is not awaiting these multiple async calls, so the next lines will execute without awaiting the result of the Promises. This is causing confusion in execution order logic of your code, behaving different than what you are expecting. Actually the function getCurrentCost() is ending before the Promises inside the loop resolves.

One way to solve your problem is replacing the .forEach() with .map(), which will return several Promises that will be awaited will Promise.all(), behaving the way it's expected.

//don't forget to turn the function async, so you can use await keyword.
async getCurrentCost() {

  let sum = 0;  
  let existingEntries = JSON.parse(localStorage.getItem("walletData"));
  if (existingEntries == null) existingEntries = [];
    
  await Promise.all(existingEntries.map(async (el) => {
    const coin = await this.coincapService.getCoin(el.id)
    currentCostArr.push(coin.priceUsd * coin.amount)
  })
  
  return currentCostArr
}
Jone Polvora
  • 2,184
  • 1
  • 22
  • 33
  • but is there a way to assign currentCostArr to the external variable to use in another function? Because as a result I get promise{pendig} – roninbony Apr 03 '22 at 13:51
  • 2
    @roninbony, async functions **always** return Promises, that *resolve* with the returned value of the async function itself. To use this value you need to chain a `then()` method or - with a more modern syntax - you need to `await` the async function. In this case `getCurrentConst().then(result => {console.log(result)})`. The `result `argument - that is automatically passed to `then()` - is the resolved value of the async function which `then()` is chained to (in this case `result` is the **currentCostArr** array), so inside the `then()` block you can assign `result` to an external variable. – cheesyMan Apr 03 '22 at 16:01
0

Your forEach loop pushes values in you array asynchronously.

You calculate the sum before you get your array filled up with values.

cheesyMan
  • 1,494
  • 1
  • 4
  • 13
  • but how shall I do in that case? I understand that I should put await somewhere? but clearly a dont understand where – roninbony Apr 03 '22 at 00:26
  • I don't think the `forEach` method is the one to go with. You need to create a loop of promises. Take a look at this link: https://stackoverflow.com/questions/40328932/javascript-es6-promise-for-loop – cheesyMan Apr 03 '22 at 00:47