I'm having issues understanding how to work around Javascript's asynchronous behavior in a forEach loop. This issue is quite complex (sorry), but the idea of the loop is as followed:
- Loop through every item in an array
- Make an HTTP request from a provider script
- I then need to multiply every element of the array by a constant
- Assign the new array to an item in an object
- After the loop, take all the arrays and add them together into one array
The data will be assigned to the indvCoinPortfolioChartData array
I'm looking for any flaws in my event loop. I believe the battle is making this task synchronous, making sure my data is assigned before aggregating data.
The issue
When I'm adding all the arrays together, ONE dataset isn't summed up (I think because it's still being processed after the function is called). There is no error, but it doesn't have all the coin data in the final aggregated array.
This is the issue I see in the aggregatePortfolioChartData function. It begins the for loop with only 2 items in the array, and then later shows 3. The third item was not processed until after the for loop started.
image of console log (logged from aggregatePortfolioChartData function)
debug log when aggregation is successful
var indivCoinPortfolioChartData = {'data': []};
for(var i = 0; i < this.storedCoins.Coins.length; i++)
{
let entry = this.storedCoins.Coins[i];
localThis._data.getChart(entry.symbol, true).subscribe(res => {localThis.generateCoinWatchlistGraph(res, entry);});
localThis._data.getChart(entry.symbol).subscribe(res => {
if(entry.holdings > 0)
{
let data = res['Data'].map((a) => (a.close * entry.holdings));
indivCoinPortfolioChartData.data.push({'coinData': data});
localThis.loadedCoinData(loader, indivCoinPortfolioChartData);
}
else
{
localThis.loadedCoinData(loader, indivCoinPortfolioChartData);
}
});
}
Loaded Coin Data
loadedCoinData(loader, indivCoinPortfolioChartData)
{
this.coinsWithData++;
if(this.coinsWithData === this.storedCoins.Coins.length - 1)
{
loader.dismiss();
this.aggregatePortfolioChartData(indivCoinPortfolioChartData);
}
}
aggregatePortfolioChartData
aggregatePortfolioChartData(indivCoinPortfolioChartData)
{
console.log(indivCoinPortfolioChartData);
var aggregatedPortfolioData = [];
if(indivCoinPortfolioChartData.data[0].coinData)
{
let dataProcessed = 0;
for(var i = 0; i < indivCoinPortfolioChartData.data[0].coinData.length; i++)
{
for(var j = 0; j< indivCoinPortfolioChartData.data.length; j++)
{
let data = indivCoinPortfolioChartData.data[j].coinData[i];
if(data)
{
aggregatedPortfolioData[i] = (aggregatedPortfolioData[i] ? aggregatedPortfolioData[i] : 0) + data;
dataProcessed++;
}
else
{
dataProcessed++;
}
}
if(dataProcessed === (indivCoinPortfolioChartData.data[0].coinData.length) * (indivCoinPortfolioChartData.data.length))
{
console.log(dataProcessed + " data points for portfolio chart");
this.displayPortfolioChart(aggregatedPortfolioData);
}
}
}
}
Thank you for helping me get through this irksome issue.