简体   繁体   中英

how to force a call to be synchronous in node.js

Please take a look at the code snippet below. I want the 2nd MongoDB query to be executed only after I have the results from the first one. But as you can imagine, it doesn't happen in that order.

db.collection('student_profile', function (err, stuColl) {
  //This if-else can be refactored in to a seperate function
  if (req.params.stuId == req.header('x-stuId')) {
    var stuInQuestion = student;
  } else {
    var stuInQuestionId = new ObjectID.createFromHexString(req.params.stuId);
    stuColl.findOne({
      '_id': stuInQuestionId
    }, function (err, stuInQuestionObj) {
      if (!stuInQuestionObj) {
        process.nextTick(function () {
          callback(null);
        });
      } else {
        var stuInQuestion = stuInQuestionObj;
      }
    });
  }

  stuColl.find({
    '_id': {
      $in: stuInQuestion['courses']
    }
  }).limit(25).sort({
    '_id': -1
  }).toArray(function (error, courses) {
    if (error) {
      process.nextTick(function () {
        callback(null);
      });
    } else {
      process.nextTick(function () {
        callback(courses);
      });
    }
  });
});

So what are my choices here?

  1. Is there a way to code this in a way that doesnt require any control flow libraries? If yes, can someone show me how?

  2. If this does require use of a control flow library, which one should I use? asynch, FuturesJs, anything else?

You don't need any control flow libraries, as these libraries are just using callbacks in the background.

Try something like this:

db.collection('student_profile', function (err, collection) {

  // Suppose that `firstQuery` and `secondQuery` are functions that make your
  // queries and that they're already defined.
  firstQuery(function firstCallback(err, firstRes) {

    // Do some logic here.

    // Make your second query inside the callback
    secondQuery(function secondCallback(err, secondRes) {
      // More logic here
    });
  });
});

Basically, what you want to do is call your second query from inside the callback of your first query.

This may strike you as deeply nested. If this becomes a problem, you can mitigate it by defining your functions instead of inlining all of them, and by wrapping logic inside of modules.

I would create a findStudent function and have both cases call it:

db.collection('student_profile', function (err, stuColl) {
  //This if-else can be refactored in to a seperate function
  if (req.params.stuId == req.header('x-stuId')) {
    return findStudent(student);
  } else {
    var stuInQuestionId = new ObjectID.createFromHexString(req.params.stuId);
    stuColl.findOne({
      '_id': stuInQuestionId
    }, function (err, stuInQuestionObj) {
      if (!stuInQuestionObj) {
        process.nextTick(function () {
          callback(null);
        });
      } else {
        return findStudent(stuInQuestionObj);
      }
    });
  }

  function findStudent(stuInQuestion) {
    stuColl.find({
      '_id': {
        $in: stuInQuestion['courses']
      }
    }).limit(25).sort({
      '_id': -1
    }).toArray(function (error, courses) {
      if (error) {
        process.nextTick(function () {
          callback(null);
        });
      } else {
        process.nextTick(function () {
          callback(courses);
        });
      }
    });
  }
});

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