2016-02-26 32 views
0

我想对使用环回设计的其中一个API进行同步呼叫。这里是我的代码:环回:对环回api进行同步呼叫

router.get('/friends', function(req, res, Array) { 
    var friendsList = [] 
    for(var counter=0;counter<length;counter++){ 
        Model.findById(Array[counter].Id,function(err, record) { 
        if(record){ 
         friendsList.push(record); 
        } 
        }); 
       } 
       res.status(200).json(friendsList); 
}); 

现在即时得到前阵的响应,好友列表是越来越完全填充。我想让这个同步并得到正确的回应。我该怎么办?

谢谢!

+0

您无法对异步函数进行同步调用 –

+0

将res.json放在回调函数中? – tymeJV

+0

@tymeJV - 这不会工作,因为回调可能是(可能是如果你看代码)多次调用 –

回答

3

一个简单的方法来做到这一点是

  • 设置一个变量在每次回调被调用时length
  • ,由1
  • 减少这个变量,当它达到零,你处理最终回调
  • 在回调,调用res.status...

筛选:

router.get('/friends', function(req, res, array) { 
    var friendsList = []; 
    var remaining = length; 
    for(var counter=0;counter<length;counter++){ 
     Model.findById(array[counter].Id, function(err, record) { 
      if (record){ 
       friendsList.push(record); 
      } 
      remaining -= 1; 
      if (remaining == 0) { 
       res.status(200).json(friendsList); 
      } 
     }); 
    } 
}); 

为了完整性......因为你正在使用...的NodeJS使用(本机)承诺与arrow function语法

router.get('/friends', (req, res, array) => 
    Promise.all(array.map(item => 
     new Promise((resolve, reject) => 
      Model.findById(item.Id, (err, record) => 
       resolve(record || undefined) 
      ) 
     ) 
    )) 
    .then(friendsList => 
     res.status(200).json(friendsList.filter(item => 
      item !== undefined 
     )) 
    ) 
); 
+0

谢谢@Jaromanda,这真的有用。欣赏它。 –

+0

承诺方式在节点v9.2.0中与我不同步 –

+0

“承诺方式”在任何地方都不同步 - 承诺本质上是异步的。考虑到'Model.findById'已经是异步的,没有办法获得同步的结果 –

0

使用的承诺和$in运营商猫鼬:

router.get('/friends', function(req, res, arr) { 
    var promise = Model.find({ _id: { $in: arr.slice(0, length).map(function (e) { return e.Id }) } }).exec() 
    promise.then(function (friendsList) { 
     res.status(200).json(friendsList) 
    }) 
}) 

arr.slice挑选数组中的第一个length元素。 Model.find创建单个查询,这比执行多个findById查询更有效。 $in运算符接受一个I​​D数组来进行查找。 .exec()创建一个单一的承诺,这是与.then(...)解决。

+0

Model.find如何知道在每个数组项目中查找“Id”?应该有地图吗?另外,是什么让你认为猫鼬参与?(并不是说你错了,只是在发布答案之前看不到任何提及) –

+0

'$ in'运算符接受一个id数组。由于使用的语法,我假定了Mongoose。但是,大多数现代ORM支持多种对象查找和承诺的概念。对于Mongoose以外的ORM,可以使用适当的API调用。 –

+0

你错过了我的问题。原始代码表明'array'是一个'object'数组,它具有一个属性'Id' - 你的代码似乎没有传递一个Id数组,它传递的是原始对象数组的一个副本 –

1

我会使用asyncunderscore模块

var async = require('async'); 
var _ = require('underscore'); 

router.get('/friends', function(req, res, Array) { 
    var friendsList = []; 
    var waterfallFunctions = []; 
    _.each(Array, function(element) { 
     waterfallFunctions.push(function(next) { 
     Model.findById(element.Id,function(err, record) { 
      if (err) return next(err); 

      if(record){ 
      friendsList.push(record); 
      } 

      next(); 
     }); 
     }); 
    }); 

    //async waterfall calls the functions in the array in order. 
    async.waterfall(waterfallFunctions, function (err) { 
     if (err) return res.status(500); 

     res.status(200).json(friendsList); 
    }); 

}); 
0

你应该等待,直到N findById调用完成这样的解决方案是做出承诺的数组,并使用Promise.all方法。

router.get('/friends', function(req, res, Array) { 
    var friendsList = [] 
    var friendsPromises = [] 

    for (var counter=0; counter<length; counter++) { 
     var friend = Model.findById(Array[counter].Id; 
     friendsList.push(friend) 

     friend.then(function(record) { 
      if (record) { 
       friendsList.push(record); 
      } 
     }) 
    } 

    Promise.all(friendsPromises).then(function(){ 
     res.status(200).json(friendsList);  
    }) 
});