Home > Enterprise >  Why can I not return an array of objects in an async function?
Why can I not return an array of objects in an async function?

Time:11-02

In node.js I am trying to get a list of bid and ask prices from a trade exchange website (within an async function). Within the foreach statement I can console.info() the object data(on each iteration) but when I put all of this into an array and then return it to another function it passes as 'undefined'.

const symbolPrice = async() => {
    let symbolObj = {}
    let symbolList = []

  await bookTickers((error, ticker) => {
    ticker.forEach(symbol => {
      if (symbol.symbol.toUpperCase().startsWith(starts.toUpperCase())) {

        symbolObj = {
          symbol: symbol.symbol,
          bid: symbol.bidPrice,
          ask: symbol.askPrice
        }
        console.info(symbolObj);

      }

      symbolList.push(symbolObj)


    });

    const results = Promise.all(symbolList)
    return results;

  });

}

const symbolPriceTest = async() => {

  const res = await symbolPrice(null, 'ETH', true);
  console.log(res)

}

I have tried pretty much everything I can find on the internet like different awaits/Promise.all()'s. I do admit I am not as familiar with async coding as I would like to be.

CodePudding user response:

So, if the basic problem here is to call bookTickers(), retrieve the asynchronous result from that call, process it and then get that processed result as the resolved value from calling symbolPrice(), then you can do that like this:

const { promisify } = require('util');
const bookTickersP = promisify(bookTickers);

async function symbolPrice(/* declare arguments here */) {
    let symbolList = [];

    const ticker = await bookTickersP(/* fill in arguments here */);
    for (let symbol of ticker) {
        if (symbol.symbol.toUpperCase().startsWith(starts.toUpperCase())) {
            symbolList.push({
                symbol: symbol.symbol,
                bid: symbol.bidPrice,
                ask: symbol.askPrice
            });
        }
    }
    return symbolList;
}

async function symbolPriceTest() {

  const res = await symbolPrice(null, 'ETH', true);
  console.log(res)

}

Things to learn from your original attempt:

  1. Only use await when you are awaiting a promise.
  2. Only use Promise.all() when you are passing it an array of promises (or an array of a mixture of values and promises).
  3. Don't mix plain callback asynchronous functions with promises. If you don't have a promise-returning version of your asynchronous function, then promisify it so you do (as shown in my code above with bookTickersP().
  4. Do not guess with async and await and just throw it somewhere hoping it will do something useful. You MUST know that you're awaiting a promise that is connected to the result you're after.
  5. Don't reuse variables in a loop.
  6. Your original implementation of symbolPrice() had no return value at the top level of the function (the only return value was inside a callback so that just returns from the callback, not from the main function). That's why symbolPrice() didn't return anything. Now, because you were using an asynchronous callback, you couldn't actually directly return the results anyway so other things had to be redone.

CodePudding user response:

Just a few thoughts on organization that might be reused in other contexts...

Promisify book tickers (with a library, or pure js using the following pattern). This is just the api made modern:

async function bookTickersP() {
  return new Promise((resolve, reject) => {
    bookTickers((error, ticker) => {
      error ? reject(error) : resolve(ticker);
    })
  });
}

Use that to shape data in the way that the app needs. This is your app's async model getter:

// resolves to [{ symbol, bid, ask }, ...]
async function getSymbols() {
  const result = await bookTickersP();
  return result.map(({ symbol, bidPrice, askPrice }) => {
    return { symbol: symbol.toUpperCase(), bid: bidPrice, ask: askPrice }
  });
}

Write business logic that does things with the model, like ask about particular symbols:

async function symbolPriceTest(search) {
  const prefix = search.toUpperCase();
  const symbols = await getSymbols();
  return symbols.filter(s => s.symbol.startsWith(prefix));
}

symbolPriceTest('ETH').then(console.log);
  
  • Related