简体   繁体   中英

Express.js Route Handler Execution Order

I am trying to query some documents from my MongoDB database, then add the documents to an array, and then send it to a rendered view. However, it seems that the line that I have to render the page is getting executed before the db query is completed. Below is the code:

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

I am very new to using Express, so if someone could help me to get the query to execute, and then the page to render, it would be greatly appreciated. Currently, where I log the posts array to console, the posts array is empty (as it is executing before the query is completed). Thanks

EDIT: When using the async/await approach (and some debugging), the 2 is now being logged to console before the 1 as expected. However, the 0 is being logged to console after 1 and 2. Could someone help me to resolve this please? Thanks

This happens because I/O operations are asynchronous operations. You must wait for your db response and then send it back to client. You are sending res.render outside find callback, which results in sending response to client before your db returns something. Put your res.render inside find callback so you will be sure you will only send your response to client after db get your docs.

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

I have been coding a lot in express lately, and sometimes the issue when querying the database is that it returns a promise. You can either provide a callback or use ES6 async/await as shown below. Hope this helps!

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM