如何处理Node中多个异步回调的结果

时间:2016-01-07 15:01:30

标签: javascript node.js asynchronous node-async

我在Node中处理一个涉及多个async.map调用的场景,其中一个调用嵌套在_.map函数中,因为我需要访问嵌套数组。我正在努力将这些调用的结果正确地组合成一个我最后返回的数组。

有关该方案的更多细节:

我从userId开始,查询我的游戏数据库,找到与此userId相关联的所有games。我为每场比赛拉gameIddescription

然后我查询每个游戏的gameId以查找与每个游戏相关联的所有userId。我从这些结果中过滤了原始的userId

接下来,我为每个userId查询我的用户数据库,以获取用户emailname等详细信息。 (注意:这是_.map发挥作用的地方,因为userId嵌套在一个数组数组中;每个内部数组代表一个游戏。)

最后一步,也是我挣扎的地方,就是如何将这些结果结合起来并归还它们。我最后想要的数组如下所示。一系列游戏对象。每个游戏对象都有gameIddescriptionusers属性。 users是与该游戏相关联的一系列用户,并且具有idemailname属性。

[
  {
    gameId: 'dfh48643hdgf',
    description: 'lorem ipsum...',
    users: [
      {
        id: 1,
        email: 'test@example.com',
        name: 'John Doe'
      },
      {
        id: 7,
        email: 'sample@example.com',
        name: 'Jane Smith'
      }, ...
    ]
  }, ...
]

下面是我目前的代码(注意:此代码块实际上是更大async.series调用的一部分):

sharedGames: function(next) {
  db.games.index({userId: userId},
    function(err, gamesData) {
      if (err) {
        logger.warn('Error retrieving games for userId %d', userId, err);
        next(err, null);
      } else {
        gamesData = _.map(gamesData, function(game) {
          return {
            gameId: game.id,
            description: game.description,
            users: []
          };
        });
        async.map(gamesdata,
          function(item, callback) {
            db.gameDetails.getGameUsers({gameId: item.gameId},
              function(err, users) {
                if (err) {
                  callback(err, null);
                } else {
                  callback(null, _.without(users.userIds, Number(userId)));
                }
              }
            );
          },
          function(err, results) {
            if (err) {
              next(null, null);
            } else {
              var flattenedResults = _.chain(results)
                .flatten()
                .uniq()
                .value();
              async.map(flattenedResults, function(user, callback) {
                db.users.getById(user, function(err, userDetails) {
                  if (err) {
                    callback(err, null);
                  } else {
                    callback(null, _.pick(userDetails, 'id', 'email', 'name'));
                  }
                });
              }, function(err, users) {
                if (err) {
                  next(null, null);
                } else {
                  _.each(results, function(result, index) {
                    _.each(result, function(user) {
                      var customerDetails = _.find(customers, function(u) {
                        return u.id === user;
                      });
                      gamesData[index].users.push(userDetails);
                    });
                  });
                  console.log(gamesData);
                  next(null, gamesdata);
                }
              });
            }
          }
        );
        next(null, []);
      }
    }
  );
}

1 个答案:

答案 0 :(得分:0)

所以你绝对可以用async.auto完成你所描述的内容。从他们的文档中查看:

async.auto({
get_data: function(callback){
    console.log('in get_data');
    // async code to get some data
    callback(null, 'data', 'converted to array');
},
make_folder: function(callback){
    console.log('in make_folder');
    // async code to create a directory to store a file in
    // this is run at the same time as getting the data
    callback(null, 'folder');
},
write_file: ['get_data', 'make_folder', function(callback, results){
    console.log('in write_file', JSON.stringify(results));
    // once there is some data and the directory exists,
    // write the data to a file in the directory
    callback(null, 'filename');
}],
email_link: ['write_file', function(callback, results){
    console.log('in email_link', JSON.stringify(results));
    // once the file is written let's email a link to it...
    // results.write_file contains the filename returned by write_file.
    callback(null, {'file':results.write_file, 'email':'user@example.com'});
}]
}, function(err, results) {
    console.log('err = ', err);
    console.log('results = ', results);
});

因此,如果您遵循相同的方法,您可以通过在每次调用时注入更多信息来获取游戏对象数组。您也可以使用async.waterfall。希望它有所帮助