如何确保在从Mongoose中的函数返回之前执行异步调用?

时间:2015-07-30 16:21:30

标签: javascript node.js mongodb asynchronous mongoose

我是mongoose的新手,为了防止ASYNC OF HELL,我来到了一个名为async的npm包中。我使用了async npm包的async.series,我的代码以下面给出的格式查看

var userId=1234
function findUser(callback){
  user.findOne({userId:userId}).exec(function(err,userData){
         //Some Logic
   var schoolId=123;
   var schoolName=findSchool(123);     
   findStudents(schoolName);

   var schoolId=1234;
   var schoolName=findSchool(123);     
   findStudents(schoolName);

   callback(null);
  });
}

function findSchool(schoolId){
 school.findOne({schoolId:schoolId}).exec(function(err),schoolDetails){
    //Some Logic  
  });
    var schoolName="XYZ High School"
    return(schoolName);
}

 function findStudents(schoolName){
  student.findOne({schoolName:schoolName}).exec(function(err),studentDetails{
    //Some Logic  
  });
 }

 async.series([findUser],function(err){
     // for Error Handling
    }

这里我使用异步系列函数来阻止HELL的ASYNC。我在异步系列调用中调用findUser函数,该函数使用User从我的userId模型中查找用户详细信息,然后调用findSchool函数 findUser函数中找到SchoolId模型中给定School的学校详细信息。函数返回通话后,我尝试使用schoolName模型上的findStudents函数根据特定Student找到学生。

对不同的schoolId重复该过程。当我调用findSchool函数时,我的问题出现了。由于它在findOne模型上有异步调用(school),因此即使在模型完成schoolName之前,我也能够返回findOne的值。

有没有办法确保给定的函数findSchoolschoolName成功完成之前不会返回school.findOne()的值?只是为了增加更清晰度,我不希望到我的返回语句里面 findOne函数的findSchool

2 个答案:

答案 0 :(得分:0)

我认为,

Async.each或async.waterfall应该可以解决这个问题。

这里最重要的是你在异步函数中使用return语句,它将在异步函数实际完成之前返回,因此它们不会传递你需要的东西。

您必须为此使用异步函数和回调。您仍然可以在代码中将功能分开,但是您必须添加回调函数而不是返回。

答案 1 :(得分:0)

您仍然应该使用async,但您需要async.waterfall。以下是您需要考虑的事项:

调用async函数的主要方法:

var getInformation = function(){
  async.waterfall([
    //Array of your functions in order, we will be back here later
  ], function (err) {
       if(err){
         console.log(err);
       }else{
         console.log('Everything OK!');
     }
  );
}

然后你需要你的函数async友好,这意味着你应该使用回调并将你的数据从一个函数提供给另一个函数。像这样:

function findUser(callback){
  //Do something
  if('Everything OK'){
    callback(err, yourData); //err should be null if everything is OK and yourData should be the data that you wanna use in your next function. e.g. schoolId 
  }else{
    callback(err); //Something was wrong, "err" should have something different to null
  }
}

function findSchool(callback, schoolId){ //Note that we receive the parameter schoolId here but not in the first function
  //Do something
  if('Everything OK'){
    callback(err, yourData); //err should be null if everything is OK and yourData should be the data that you wanna use in your next function. e.g. schoolName 
  }else{
    callback(err); //Something was wrong, "err" should have something different to null
  }
}

function findStudents(callback, schoolName){
  //Do something
  if('Everything OK'){
    callback(err); //err should be null if everything is OK if this is the last function maybe we don't need to send back more data from here 
  }else{
    callback(err); //Something was wrong, "err" should have something different to null
  }
}

然后你应该用你的main方法调用你的函数:

var getInformation = function(){
  async.waterfall([
    findUser,
    findSchool,
    findStudents
    //Note that there is no need to tell the functions the parameters they are sending or receiving here
  ], function (err) {
       if(err){
         console.log(err);
       }else{
         console.log('Everything OK!');
     }
  );
}

就是这样,你有三个应该一个接一个地执行的功能,并且不需要回调地狱。