Express.js路由处理程序执行顺序

时间:2018-03-03 14:10:49

标签: javascript node.js express

我正在尝试查询MongoDB数据库中的某些文档,然后将文档添加到数组中,然后将其发送到渲染视图。但是,似乎我必须在db查询完成之前执行呈现页面的行。以下是代码:

router.get('/blog/:username/:postid', async function(req, res, next) {
  var posts = [];

  await collPosts.find( { $and : [{ postid : parseInt(req.params.postid) }, { username : req.params.username }] }, function(err, docs) {
    docs.each(function(err, doc) {
      if (doc) {
        var renderedTitle = renderer.render(parser.parse(doc.title));
        var renderedBody = renderer.render(parser.parse(doc.body));

        var post = { postid : doc.postid, username : doc.username, created : doc.created, modified : doc.modified, title : renderedTitle, body : renderedBody };
        posts.push(post);
        console.log("0"); // EDIT
      } 
    });
    console.log("1"); // EDIT
  });

  console.log("2"); // EDIT
  res.render('index', { title : 'Post Results', Posts : posts });
});

我是使用Express的新手,所以如果有人可以帮助我执行查询,然后再渲染页面,我们将不胜感激。目前,我将posts数组记录到控制台,posts数组为空(因为它在查询完成之前执行)。感谢

编辑:当使用async / await方法(以及一些调试)时,2正在按预期在1之前登录到控制台。但是,在1和2之后0正在登录到控制台。有人可以帮我解决这个问题吗?感谢

2 个答案:

答案 0 :(得分:2)

这是因为I / O操作是异步操作。您必须等待数据库响应,然后将其发送回客户端。您正在res.render之外发送find回调,这会导致在您的数据库返回之前向客户端发送响应。将res.render置于find回调内,这样您就可以确保在获取文档后,您只会将回复发送给客户。

router.get('/blog/:username/:postid', function(req, res, next) {
  var posts = [];

  collPosts.find( { $and : [{ postid : parseInt(req.params.postid) }, { username : req.params.username }] }, function(err, docs) {
    docs.each(function(err, doc) {
      if (doc) {
        var renderedTitle = renderer.render(parser.parse(doc.title));
        var renderedBody = renderer.render(parser.parse(doc.body));

        var post = { postid : doc.postid, username : doc.username, created : doc.created, modified : doc.modified, title : renderedTitle, body : renderedBody };
        posts.push(post);
      } 
    });
    console.log(posts);
    res.render('index', { title : 'Post Results', Posts : posts });
  });
});

答案 1 :(得分:0)

我最近在express中编写了很多代码,有时查询数据库时的问题是它返回了一个promise。您可以提供回调或使用ES6 async / await,如下所示。希望这有帮助!

router.get('/blog/:username/:postid', async function(req, res, next) {
  var posts = [];

  await collPosts.find( { $and : [{ postid : parseInt(req.params.postid) }, { username : req.params.username }] }, function(err, docs) {
    docs.each(function(err, doc) {
      if (doc) {
        var renderedTitle = renderer.render(parser.parse(doc.title));
        var renderedBody = renderer.render(parser.parse(doc.body));

        var post = { postid : doc.postid, username : doc.username, created : doc.created, modified : doc.modified, title : renderedTitle, body : renderedBody };
        posts.push(post);
      } 
    });
  });

  console.log(posts);
  res.render('index', { title : 'Post Results', Posts : posts });
});