2015-11-01 92 views
0

我在找一个答案,发现this。像在jQuery中有when函数。使用一些准则来同步异步调用我在节点 中使用async.js以下是代码。如何从异步函数返回db调用的值

async.forEach(dateInDateFormat, function(item, callback) { 
     console.log(moment(item.startDate).toDate()); 
     var result = Trip.aggregate([{ 
      "$unwind": "$trips" 
     }, { 
      "$match": { 
       "trips.startTime": { 
        "$gte": moment(item.startDate).toDate(), 
        "$lte": moment(item.endDate).toDate() 
       } 
      } 
     }, { 
      "$group": { 
       "_id": { 
        "date": { 
         "$dayOfMonth": "$trips.startTime" 
        } 
       }, 
       "distance": { 
        "$sum": "$trips.distance" 
       } 
      } 
     }]); 
     result.exec(function(err, doc) { 
      console.log(doc); 
     }); 
     console.log("Executing callback"); 
     callback(); 
    }, function(error) { 
     console.log("Loop over"); 
    }); 

这是输出。

Executing callback 
Loop over 
[ { _id: { date: 23 }, distance: 0 }, 
{ _id: { date: 22 }, distance: 0 }, 
{ _id: { date: 21 }, distance: 0 } ] 
[ { _id: { date: 29 }, distance: 210 }, 
    { _id: { date: 27 }, distance: 210 }, 
    { _id: { date: 26 }, distance: 210 }, 
    { _id: { date: 25 }, distance: 0 } ] 
[] 

正如你所看到的。在获取数据之前执行回调和循环。我无法使用res.send()将它发送回我的A​​ngular Frontend。 一个答案是你无法从异步函数中返回一个值。你只返回一个回调。在这种情况下我该怎么做? 或 如何使用async.series([])功能。因为我也使用过,甚至没有给我确切的结果。 谢谢

编辑 回答简而言之,回调函数的位置很重要。如果你在错误的地方给它,不要期待写回答。请参阅答案和评论主题中的代码以获得更好的解释。

回答

2

callback有点神奇,只是表示async.foreach已经完成了一个特定的foreach执行。我不熟悉aggregate函数或exec,所以我假设聚合构建查询,并且exec异步执行该查询。

forEach回调可以被移动到result.exec的结果。这将指示async该特定查询的执行已结束。当所有执行都结束时,函数会传递到第二个参数forEach将被执行。执行时,所有功能都已完成或出现错误,在这种情况下,您可以使用sendres

的整个流程:

  1. 创建数据的列表操作上asyncronously
  2. 在列表中执行对每一项功能(第2参数去async.forEach)asyncronously。
    1. 构建聚集查询
    2. exeucte聚集查询异步
    3. 指出async.foreach这聚集操作已经完成,通过调用callback功能
  3. callback已经呼吁在阵列异步每个项目将调用作为第三参数传递给async.forEach的函数。
  4. 将结果返回给客户端,因为所有任务都已解决。

async.forEach(dateInDateFormat, function(item, callback) { 
     console.log(moment(item.startDate).toDate()); 
     var result = Trip.aggregate([{ 
      "$unwind": "$trips" 
     }, { 
      "$match": { 
       "trips.startTime": { 
        "$gte": moment(item.startDate).toDate(), 
        "$lte": moment(item.endDate).toDate() 
       } 
      } 
     }, { 
      "$group": { 
       "_id": { 
        "date": { 
         "$dayOfMonth": "$trips.startTime" 
        } 
       }, 
       "distance": { 
        "$sum": "$trips.distance" 
       } 
      } 
     }]); 
     result.exec(function(err, doc) { 
      console.log(doc); 
      console.log("Executing callback"); 
      callback(); 
     }); 
    }, function(error) { 
     // all tasks passed to forEach have been completed, or 
     // an error has occurred 
     res.send('COMPLETE'); 
     console.log("Loop over"); 
    }); 

这太疯狂了我一个简单的操作怎么能有如此疯狂的编程流程:)

+0

好感谢您的解释,但它仍然是不明确的。如果你看到输出(我刚刚编辑输出),并看到console.logs()有问题。 console.log(“Loop over”)在打印数组之前执行。因此,在'function(error)'处发送'res.send'的想法将不起作用。你知道还有其他的工作吗? –

+0

@SarasArya你试过我的答案吗?在你的例子中,我很确定,“循环结束”执行如此之快,因为你并没有等待'result.exec'的响应。 – dm03514

+0

嘿它工作了......先看代码。我认为这是一样的。在你的第二个评论后。我通过diffChecker运行它,发现回调的位置发生了变化,这实际上是有道理的。起初很难理解答案,但代码的工作向我解释了如何。非常感谢。这将成为我异步编程历史上最重要的事情之一。 –