async API call inside forEach loop

2019-08-01 03:14发布

问题:

I ran into a problem that I cannot seem to solve, I'm guessing I'm missing some points in terms of async behaviour.

The task is relatively simple: A wallet with money in different currencies needs to be transformed into a single currency. I want to get the exchange rate from following API:

https://free.currencyconverterapi.com/api/v5/convert?q=${from}_${to}&compact=y

With ${from} being the starting currency and ${to} the target currency.

I store the different currencies in an object called positions, that looks like this:

[
    {'currency': "EUR",
    "amount": 10},
    {'currency': "CNY",
    "amount": 100},
  ]

So the task would be to transform the 100EUR and 100CNY in for example USD.

To gather the exchange rates, I want to iterate through the single positions in following function:

    collectExRates(targetCurrency) {
    let exRatesDict = {}
    this.positions.forEach( (position) => { 
      exRatesDict[position.currency] = this.parseUrl(position.currency, targetCurrency)
    });
    return exRatesDict
}

And with parseUrl being:

    parseUrl(from, to) {
    const exRateName = from + '_' + to;
    var rate;
    return fetchUrl(`https://free.currencyconverterapi.com/api/v5/convert?q=${from}_${to}&compact=y`, function(error, meta, body){
            rate = JSON.parse(body)[exRateName].val
            console.log("RATE", rate)
            return rate
        });
}

I already tried a couple of things (like creating an async forEach, Promises, async await, etc.), but I just can not get the intended result, which is to return the exchange rates dictionary mapping a currency to it's respective exchange rate.

I will be very thankful for any help.

回答1:

The problem is that async methods returns Promise and you need to wait them to resolve. The common pattern to do this is next:

Promise.all(arr.map(v => someAsyncFunc(v))).then((resolvedValues) => {
  resolvedValues.forEach((value) => {
    // Do your stuff here
  });
});

So basically you are initializing bunch of async calls, waiting for them to resolve with Promise.all and only after that preform some operations on resolved data.



回答2:

You should try something like this:

function fetchUrls(urlList) {
  let promises = [];
  for(idx in urlList) {
    promises.push(fetch(urlList[idx]));
  }
  return Promise.all(promises);
}

fetchUrls(your_list_of_urls)
.then(console.log)