Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using async/await still returns undefined

I asked recently about the asynchronous in javascript, request-promise module returns undefined. I quite understand it after someone gave the same SO question which is the How do I return the response from an asynchronous call?. I learned a lot which helps me to how properly request an api. But now I encounter the same problem even though I'm using async/await already. I put comments where I'm getting an undefined.

const request = require('request');
const rp = require('request-promise');

const MongoClient = require('mongodb').MongoClient;
const ObjectId = require('mongodb').ObjectID;

const CONNECTION_STRING = process.env.DB;
const dbName = 'fcc';
const connectionOption = { useNewUrlParser: true };

function StockHandler() {

  this.latestWithoutLike = async function(ticker, multipleStock, callback) {
    if (!multipleStock) {
      console.log('Single stock');
      let lastPrice = await getLastPrice(ticker);

      if (typeof lastPrice === 'string') {
        getLikes(ticker, false, (data) => {

          let stockData = {
            stock: data.stock,
            price: lastPrice,
            likes: data.likes
          }

          return callback({ stockData: stockData });
        });
      }
    } else {
      console.log('Multiple stock');
      let firstStockLastPrice = await getLastPrice(ticker[0]);
      let secondStockLastPrice = await getLastPrice(ticker[1]);

      if (typeof firstStockLastPrice === 'string' && typeof secondStockLastPrice === 'string') {
        let firstStockLikes = await getLikes(ticker[0], false, (data) => { return data; });
        let secondStockLikes = await getLikes(ticker[1], false, (data) => { return data; });

        console.log(firstStockLikes); // <--- undefined
        console.log(secondStockLikes); // <--- undefined
      }

    } 
  };

  this.latestWithLike = async function(ticker, multipleStock, callback) {
    if (!multipleStock) {
      console.log('Single stock');
      let lastPrice = await getLastPrice(ticker);
      console.log(lastPrice);
      if (typeof lastPrice === 'string') {
        getLikes(ticker, true, (data) => {

          let stockData = {
            stock: data.stock,
            price: lastPrice,
            likes: data.likes + 1
          }

          return callback({ stockData: stockData });
        });
      }

    } else {
      console.log('Multiple stock');
      let firstStockLastPrice = await getLastPrice(ticker[0]);
      let secondStockLastPrice = await getLastPrice(ticker[1]);
      console.log(firstStockLastPrice);
      console.log(secondStockLastPrice);
    }
  };  

}

function getLastPrice(ticker) {
  let options = {
    uri:  `https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=${ticker}&interval=1min&apikey=${process.env.ALPHA_KEY}`,
    method: 'GET',
    json: true
  }

  return rp(options)
    .then(function(parsedBody){
      let latestStockTradeTime = Object.keys(parsedBody[Object.keys(parsedBody)[1]])[0];
      let closingPrice = parsedBody[Object.keys(parsedBody)[1]][latestStockTradeTime]['4. close'];
      return closingPrice;
    })
    .catch(function(error){
      return error;
    })
}

function getLikes(ticker, likeStatus, callback) {
  MongoClient.connect(CONNECTION_STRING, connectionOption, (err, client) => {

    if (err) callback(err);

    const db = client.db(dbName);
    const collection = db.collection('stock');

    if (!likeStatus) {
      try {
        collection.findOne(
          { stock: ticker.toUpperCase() },
          { upsert: true },
          (err, result) => {
            if (result === null) {
              collection.insertOne(
                { stock: ticker.toUpperCase(), likes: 0 },
                { upsert: true },
                (err, result) => {
                  return callback(result.ops[0]);
                }
              ); 
            } else {
                return callback(result);
            }
          }
        );
      } catch (e) {
          return callback({ error: e });
      }  
    } 
    else {
      try {
        collection.findOneAndUpdate(
          { stock: ticker.toUpperCase() },
          { $inc : { likes: 1 } },
          { upsert: true, new: true },
          (err, data) => {
            return callback(data.value);
          }
        );
      } catch (e) {
          return callback({ error: e });
      }
    }

  });
};

module.exports = StockHandler;
like image 249
isemaj Avatar asked Nov 20 '18 02:11

isemaj


1 Answers

If you're defining a function with asynchronous behavior, you can use async/await or Promise chaining. Inside an async function, you can use await or chain .then() to wait for asynchronous responses. Your function returns a Promise with the resolved value or error to its callers.

async function getLikes() {
  const likes = await db.get('myLikes'); // this db method returns a Promise
  // ...
  return likes; // will return a Promise resolving likes from db or an error if there is one
}

async function logLikes() {
  const result = await getLikes();
  console.log(result);
}

If you're consuming an asynchronous function and do not await or chain the response like in this example...

async function getLikes() {
  const likes = db.get('myLikes'); // uh oh, this is asynchronous
  // ...
  return likes;
}

... the thread can move on before the return value is assigned to like. That may be where you're seeing undefined issues.

like image 106
stealththeninja Avatar answered Oct 03 '22 01:10

stealththeninja