Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
164 views
in Technique[技术] by (71.8m points)

javascript - How to ensure an asynchronous call is executed before returning from a function in Mongoose?

I am new to mongoose and in order to prevent ASYNC OF HELL I came Across an npm package called async. I have used the async.series of the async npm package and my code looks in the given format given below

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
    }

Here I am using an async series function to prevent the ASYNC of HELL. I am calling findUser function in the async series call which is find the user details from my User model using the userId and then I am calling the findSchool function inside the findUser function which finds school details for the given SchoolId in School model. Once the function returns the call I am trying to find the students based on a particular schoolName using the findStudents function on the Student model.

The process is repeated for a different schoolId. My Issue comes when I call the findSchool function. Since it has a asynchronous call (findOne) on the school model, I am able to return the value of the schoolName even before the findOne is completed for the model.

Is there a way to ensure that the given function findSchool doesn't return the value of the schoolName until the school.findOne() has completed successfully? Just to add more clarity I don't want to my return statement inside the findOne of the findSchool function.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You should still use async but you need async.waterfall for that. Here is what you need to consider:

A main method to call your async function:

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

Then you need your functions to be async friendly, that means you should use callbacks and give your data from one function to another. Something like this:

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

Then you should call your functions in your main method:

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

And that's it, you have 3 functions that should be executed one after the other and no callback hell is needed.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...