我想了解内部和外部回调函数中promise的行为

时间:2019-06-12 20:35:28

标签: javascript node.js asynchronous async-await

我对NodeJS相当陌生,并试图理解异步,等待和承诺。如果我将resolve()置于'con.query'的回调范围之外(仍在新的Promise范围之内),则likes变量未定义。仅当resolve()在回调内部时才填充它。为什么会这样?范例:

//WORKS
async function findLikes(q, req, res){

  var likes_q = `SELECT * FROM PublicStoryLike WHERE authorId = 
${req.body.token_id}`;
  var likes;
  var lookup = {};

  //const query = util.promisify(con.query).bind(con);

  const query = new Promise((resolve, reject) => {
    con.query(likes_q, (err, result) => {
    likes = JSON.stringify(result);
    resolve();    //INSIDE con.query
  });

  })

//DOESN'T WORK
async function findLikes(q, req, res){

  var likes_q = `SELECT * FROM PublicStoryLike WHERE authorId = 
${req.body.token_id}`;
  var likes;
  var lookup = {};

  //const query = util.promisify(con.query).bind(con);

  const query = new Promise((resolve, reject) => {
    con.query(likes_q, (err, result) => {
        likes = JSON.stringify(result);

     });
     resolve(); //OUTSIDE con.query 
  })

2 个答案:

答案 0 :(得分:0)

第二个代码块中的问题是您正在立即兑现承诺。您不必等待con.query方法完成。

由于您要使用async / await并且您似乎正在使用util.promisify,因此我建议以下内容:

async function findLikes(q, req, res) {
  const likes_q = `SELECT * FROM PublicStoryLike WHERE authorId =  ${
    req.body.token_id
  }`;

  const query = util.promisify(con.query).bind(con);
  const likes = await query(likes_q);

  // ....
}

您可以看到不需要手动创建Promise。这就是util.promisify会为您做的。您只需为此await

编辑:通过进一步查看您的代码,我发现findLikes就像一条明确的路线。通常,我不建议将Web请求逻辑与数据访问层结合使用。

我建议您通过使findLikes为独立的异步函数来将它们分开:

async function findLikes(authorId) {
  const likes_q = `SELECT * FROM PublicStoryLike WHERE authorId =  ${
    authorId
  }`;

  const query = util.promisify(con.query).bind(con);

  return await query(likes_q);
}

然后在您的路线中:

async function findLikesRoute(q, req, res){
  const likes = await findLikes(req.body.token_id);
  //... work with the data
}

这将为您带来关注点分离的好处。例如,如果假设您要更改公开数据的方式,该怎么办?现在,您现在不希望通过GraphQL公开它,而不是通过这种明确的途径公开它?

如果您将数据访问逻辑分开,那将非常容易。

答案 1 :(得分:0)

让我们忘记诺言。误解与此处的回调有关:您的情况可以说明为:

  function works(callback) {
     setTimeout(function() {
        console.log("inside timeout");
        callback("result");
     }, 1000);
  }

  function doesnt(callback) {
    setTimeout(function() {
      console.log("inside timeout");
    }, 1000);
    callback();
  }

  works(function(result) { console.log("called back"); });

在工作版本中,当调用内部回调时,您将回调外部回调,这意味着您的情况是从数据库到达的结果。

在非工作版本中,您直接回调回调,但是计时器(或数据库调用)尚未完成,因此结果还不存在。


通常不应使用全局变量,尤其是在涉及异步时。您的likes变量将导致您(并且已经)引起您的头痛,只需将其完全删除即可。而是使用所需的值 resolve 承诺(或回调)。这样,您可以轻松检测到错误:

  getResult(function(result) {
    callback(result); // works, result is ready
  });

  callback(result); // does not work, throws an error

在您的情况下,它将是:

 async function findLikes(q, req, res){

   const query = `SELECT * FROM PublicStoryLike WHERE authorId = ${req.body.token_id}`;



   return new Promise((resolve, reject) => {
    con.query(query, (err, result) => {
       if(err) reject(err) else resolve(result);
    });
   });
 }

 findLikes(/*...*/)
   .then(likes => {
     // Work with likes here!
   });