Promises和Q - 使用forEach完成一系列功能

时间:2016-02-15 12:23:54

标签: javascript mongodb promise q

对于如何最好地写这个有点困惑 - 希望这个描述很清楚。

我有一个forEach函数,我在其中浏览一些JS对象数据,并为每个项目执行一个函数:

found.forEach(function(item) {
      processData(item['userID']);
});

在这个processData函数中,我正在使用MongoDB find()调用。

var processData = function(userIDSelected) {

    User.find( {_id: userIDSelected},
           {gender: 1, country:1}, function(req, foundUser) {
            processUserInfo(foundUser[0]['gender']);
    });
}

我遇到的问题是,如果考虑到每个呼叫将依次运行processUserInfo,我如何等待forEach中的所有内容完成。

我已经看过使用Q库和Q.all然而这不起作用。

是否有Q函数等待长链中的所有内容完成?

由于

2 个答案:

答案 0 :(得分:1)

Q.all

  

返回一个使用包含每个承诺的履行价值的数组来履行的承诺,或者被拒绝的拒绝理由与第一个被拒绝的承诺相同。

Q.allSettled

  

返回使用一系列承诺状态快照实现的承诺,但仅在所有原始承诺已经解决后,即变为满足或被拒绝。

所以你要做三件事:

  1. 修改processData以及可能调用MongoDB,以便最终返回processData返回异步操作的承诺。 (道歉,我不熟悉MongoDB。Alnitak says对于现代版本,如果你不提供回调,MongoDB会返回一个promise(很好!)。否则,this question and its answers may help返回一个promise对于基于回调的API。)

  2. 使用map代替forEach获取所产生承诺的数组。

  3. 在该承诺数组上使用Q.allQ.allSettled

  4. 如果User.find在未指定回调的情况下返回承诺,则#1看起来某事,如下所示:

    var processData = function(userIDSelected) {
    
        return User.find(
               {_id: userIDSelected},
               {gender: 1, country:1}
        ).then(function(req, foundUser) { // <== Check these args with the MongoDB docs!
            return processUserInfo(foundUser[0]['gender']);
        });
    };
    

    如果没有,您可以使用Q.defer

    自行完成
    var processData = function(userIDSelected) {
        var d = Q.defer();
        User.find(
               {_id: userIDSelected},
               {gender: 1, country:1},
               function(req, foundUser) {
            processUserInfo(foundUser[0]['gender']);
            d.resolve(/*...data could go here...*/); // You'd use d.reject() if there were an error
        });
        return d.promise;
    };
    

    然后这是2和3的样子:

    Q.all(found.map(function(item) { // Or Q.allSettled
        return processData(item);
    }))
    .then(...)
    .catch(...);
    

    如果processData仅使用其第一个参数(忽略任何额外的参数),则可以抛弃中间函数:

    Q.all(found.map(processData)) { // Or Q.allSettled
    .then(...)
    .catch(...);
    

    ...但如果processData忽略了额外的参数,因为map将传递三个(值,其索引和数组)。

答案 1 :(得分:0)

您编码的方式我可以假设userID是来自MongoDB的ObjectId

如果是这种情况,只要found不为空,这就可以正常工作,否则您的用户将永远等待服务器响应。

processData(
  // Retrieve an object 
  // {
  //   $in: [ObjectId, ObjectId, ...]
  // }
  // 
  found.reduce(
    function(query, user) {
      return query.$in.push(user.userID), query;
    },
    {$in: []}
  )
);

您可以获得有关$in运算符here的更多信息。