Search code examples
javascriptnode.jsasync-awaitlodash

Module returns empty array


I have a simple module return which makes a bunch of API calls to retrieve data and then return it

export default async function getCandles(coins) {
  let data = [];
  _.forEach(coins, async coin => {
    let candles1h = await client.candles({
      symbol: coin,
      interval: "1h",
      limit: 500
    });
    let candles2h = await client.candles({
      symbol: coin,
      interval: "2h",
      limit: 500
    });
    let candles4h = await client.candles({
      symbol: coin,
      interval: "4h",
      limit: 500
    });
    let candles1d = await client.candles({
      symbol: coin,
      interval: "1d",
      limit: 500
    });

    let candles = {
      "1h": candles1h,
      "2h": candles2h,
      "4h": candles4h,
      "1d": candles1d
    };

    data.push({ coin: candles });
  });

  return data;
}

And I've got a test file which inputs the array parameter and sends it

async function test() {
  let candles = await getCandles(coins);

  console.log(candles);
}

When I call the test function, the output is just an empty array. What am I doing wrong here?


Solution

  • The problem is that getCandles() has no way of knowing when each of the batches of async functions lodash.forEach() creates resolves.

    One solution might be to call your batches of async functions using Promise.all(). Promise.all() is awaitable and enables multiple calls to be sent simultaneously, rather than sequentially.

    See below for a rough example.

    // Get Candles.
    const getCandles = async symbol => {
      const intervals = ['1h', '2h', '4h', '1d']
      const limit = 500
      const candles = await Promise.all(intervals.map(async interval => await client.candles({symbol, interval, limit})))
      return candles.reduce(async (c, x, i) => {
        c[intervals[i]] = x
        return c
      }, {})
    }
    
    // Get Coins.
    const getCoins = async symbols => {
      const coins = symbols.map(async symbol => ({coin: await getCandles(symbol)}))
      return await Promise.all(coins)
    }
    
    // Test.
    const test = async () => await getCoins(symbols)