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

Posted

技术标签:

【中文标题】如何确保在从 Mongoose 中的函数返回之前执行异步调用?【英文标题】:How to ensure an asynchronous call is executed before returning from a function in Mongoose? 【发布时间】:2015-10-22 03:03:16 【问题描述】:

我是 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 函数,该函数使用userId 从我的User 模型中查找用户详细信息,然后我调用findSchool 函数inside @987654330 @ 函数在School 模型中查找给定SchoolId 的学校详细信息。一旦函数返回调用,我将尝试使用 Student 模型上的 findStudents 函数根据特定的 schoolName 查找学生。

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

有没有办法确保给定函数findSchoolschool.findOne() 成功完成之前不会返回schoolName 的值?只是为了更清楚地说明我不想findSchool 函数的findOne 内部 我的返回语句。

【问题讨论】:

使用异步瀑布 - github.com/caolan/async#waterfall 【参考方案1】:

您仍应使用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!');
     
  );

就是这样,你有 3 个函数应该一个接一个地执行,不需要回调地狱。

【讨论】:

嗨 Gesser 如果我的 findUser 多次调用我的 findSchool 函数怎么办。那里会有异步瀑布吗?假设我有多个 SchoolId,我在我的 findUser 函数中放置了一个 for 循环,在这种情况下异步瀑布有助于吗? @shubhamagiwal 很高兴它对您有所帮助。你应该阅读async doc,你可以用它做任何与工作流相关的事情。【参考方案2】:

我认为 Async.each 或 async.waterfall 应该可以解决问题。

这里的主要问题是您在异步函数中使用了 return 语句,它将在异步函数实际完成之前返回,因此它们不会传递您需要的内容。

您必须为此使用异步函数和回调。你仍然可以在你的代码中按照你想要的方式分离你的函数,但是你必须添加回调函数而不是返回。

【讨论】:

以上是关于如何确保在从 Mongoose 中的函数返回之前执行异步调用?的主要内容,如果未能解决你的问题,请参考以下文章

如何在从 Meteor.method 返回之前等待子流程结果

在从 HttpClient 请求获得的对象转换新类型之前,如何使用 rxjs 映射来改变对象中的数据?

在从函数返回之前等待 Firebase 加载

如何编写一个在“返回”之前等待事件触发的 node.js 函数?

如何在从函数返回的地图中打印值[重复]

Python C 模块函数参数引用计数