node.js + socket.io +结果需要多个数据库调用

时间:2012-09-28 20:17:37

标签: javascript node.js asynchronous redis socket.io

我需要帮助。

我一直试图用node.js和socket.io来绕过异步编程一天。我知道我需要一些流控制,但我似乎不明白如何正确实现它。

我有一个redis数据存储区,其中的模块存储在一个集合中,例如'moda','modb' 这些模块的实例是'moda:instances',在'modb:instances'中,这些实例的属性存储在'moda:instancea'和'modb:instanceb'中作为哈希。

我想获得以下json:

"moda": {"instancea": {"property1": "value1", "property2", "value2"}}, "modb": {"instanceb": {"property1": "value1"}}

有人能给我一点正确的方向吗?

这是我目前的代码:

var io = require('socket.io').listen(2000);
var redis = require('redis').createClient();
var http = require('http');
var async = require('async');
var step = require('step');

io.sockets.on('connection', function (socket) {

var notifications = require('redis').createClient();
notifications.subscribe("notification");
notifications.on("message", function (channel, message) {
  socket.send(message);
  console.log(channel + ':' + message);
});

socket.on('modules', function(params, callback) {
  var response = {};
  async.series([

  function (callback) {
    console.log('1>');
    redis.smembers('modules', function (err, modules) {
      async.forEachSeries(modules, function(module, moduleCallback) {
        response[module] = {}

        redis.smembers(module + ':instances', function(err, instances) {
          async.forEachSeries(instances, function(instance, instanceCallback) {
            response[module][instance] = {}
            console.log('2>' + module + ':' +instance);
            instanceCallback();
          });
          moduleCallback();
        });
      });
      callback();
    });
  },
  function (callback) {
    console.log('3');
    callback();
  }

], function() {
  console.log(JSON.stringify(response));
});


});

});

此代码的输出为:

   info  - socket.io started
   debug - client authorized
   info  - handshake authorized JMMn1I8aiOMGCMPOhC11
   debug - setting request GET /socket.io/1/websocket/JMMn1I8aiOMGCMPOhC11
   debug - set heartbeat interval for client JMMn1I8aiOMGCMPOhC11
   debug - client authorized for 
   debug - websocket writing 1::
1>
3
{"moda":{}}
2>moda:instancea
2>moda:instanceb
2>modb:instancea

2 个答案:

答案 0 :(得分:0)

问题来自于事件forEachSeries需要额外的回调作为第三个参数(在整个处理完成时调用)。你不能在forEachSeries之后放一些代码,希望它一旦完成就会被调用。

以下是您修改的代码:

var response = {};
async.series([

function (callback) {
  console.log('1>');
  redis.smembers('modules', function (err, modules) {
    async.forEachSeries(modules, function(module, moduleCallback) {
      response[module] = {}

      redis.smembers(module + ':instances', function(err, instances) {
        async.forEachSeries(instances, function(instance, instanceCallback) {
          response[module][instance] = {}
          console.log('2>' + module + ':' +instance);
          instanceCallback();
        }, moduleCallback );
      });
    }, callback );
  });
},
function (callback) {
  console.log('3');
  callback();
}],
function() {
   console.log(JSON.stringify(response));
});

注意回调和moduleCallback如何用作第三个参数。输出是:

1>
2>moda:instancea
2>moda:instanceb
2>modb:instancea
3
{"moda":{"instancea":{},"instanceb":{}},"modb":{"instancea":{}}}

我猜这是你的预期。

补充说明:forEachSeries将按顺序处理所有内容,下一个操作等待前一个操作完成。这将为Redis带来大量往返。 forEach在这里应该更有效地利用流水线技术。

答案 1 :(得分:-1)

另请参阅promise概念,使用promises,您可以更加可读地配置流程。

首先,您需要准备正在使用的redis方法的承诺版本:

var promisify = require('deferred').promisify;
var RedisClient = require('redis').RedisClient;
RedisClient.prototype.psmembers = promisify(RedisClient.prototype.smembers);

然后您可以将您的流程构建为:

console.log('1>');
redis.psmembers('modules').map(function (module) {
  response[module] = {};
  return redis.psmembers(module + ':instances').map(function (instance) {
    response[module][instance] = {};
    console.log('2>' + module + ':' +instance);
  });
}).end(function () {
  console.log('3');
  console.log(JSON.stringify(response));
});

检查:https://github.com/medikoo/deferred