使用 async/await 仍然返回 undefined

Posted

技术标签:

【中文标题】使用 async/await 仍然返回 undefined【英文标题】:Using async/await still returns undefined 【发布时间】:2019-04-22 10:52:21 【问题描述】:

我最近询问了 javascript 中的异步,request-promise module returns undefined。在有人提出相同的 SO 问题(How do I return the response from an asynchronous call?)后,我非常理解。我学到了很多东西,这有助于我如何正确地请求 api。但是现在我遇到了同样的问题,即使我已经在使用async/await。我把 cmets 放在我得到 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;

【问题讨论】:

如果你想使用async/await 那么getLikes() 需要返回一个promise。 如果我不想使用async/await,还有哪些其他选项? 有很多代码需要查看。基本上,@MarkMeyer 所说的:就像同步函数一样,如果需要链接它,使用 async/await 的函数应该返回一个值,区别在于 async function() 将其返回值(或错误)包装在 Promise 中。 是不是说async function()内部调用的任何函数都需要使用await?因为我仍然很困惑,尤其是当我删除这两个上的await 时,我仍然得到undefined 【参考方案1】:

如果您要定义 a function with asynchronous behavior,则可以使用 async/await 或 Promise 链接。在异步函数中,您可以使用await 或链.then() 来等待异步响应。您的函数向其调用者返回带有解析值或错误的 Promise。

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);

如果您正在使用异步函数并且不等待或链接响应,如本例中...

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

...在将返回值分配给like 之前,线程可以继续运行。这可能是您看到undefined 问题的地方。

【讨论】:

以上是关于使用 async/await 仍然返回 undefined的主要内容,如果未能解决你的问题,请参考以下文章

Async/Await 仍然阻塞 UI?

ES7 Async/Await 陷阱

简单理解JavaScript 的async/await

正确使用带有 Await/Async 的 Promise

将 fetch 与 async/await 一起使用会返回 [object Object]

在 Firebase Cloud Functions 中使用 async/await 时返回一个 Promise