控制节点/ redis和回调的流量问题?

时间:2011-11-01 19:44:19

标签: javascript node.js redis

请问有关node和redis的控制流问题的一些建议吗? (也就是Python编码器试图习惯JavaScript)

我不明白为什么client.smembersclient.get(Redis查找)需要回调而不仅仅是语句 - 这会让生活变得非常复杂。

基本上我想查询一个集合,然后当我得到集合的结果时,我需要为每个结果执行get。 当我获得所有数据时,我需要将其广播回客户端。

目前我在两个回调中使用全局对象执行此操作,这看起来很混乱。我甚至不确定它是否安全(代码是否会在启动另一个之前等待一个client.get完成?)。

目前的代码如下:

var all_users = [];
// Get all the users for this page.
client.smembers("page:" + current_page_id, function (err, user_ids ) {
  // Now get the name of each of those users.
  for (var i = 0; i < user_ids.length; i++) {
     client.get('user:' + user_ids[i] + ':name', function(err, name) {
       var myobj = {};
       myobj[user_ids[i]] = name;
       all_users.push(myobj);  
       // Broadcast when we have got to the end of the loop, 
       // so all users have been added to the list - 
       // is this the best way? It seems messy.  
       if (i === (user_ids.length - 1)) {
           socket.broadcast('all_users', all_users); 
       }
     });       
   }
 });

但这看起来非常混乱。这真的是最好的方法吗?在调用socket.broadcast之前,如何确保所有查找都已执行?

刮擦头提前感谢任何建议。

4 个答案:

答案 0 :(得分:1)

  

我不明白为什么client.smembersclient.get(Redis查找)需要回调而不仅仅是语句 - 这会让生活变得非常复杂。

这就是Node。 (我很确定这个话题已在这里讨论了很多次,看看其他问题,它肯定在那里)

  

如何在调用socket.broadcast之前确定所有查找都已执行?

这就是回调函数中的err。这是Node的标准 - 回调中的第一个参数是错误对象(null如果一切正常)。所以只需使用这样的东西,确保没有发生错误:

if (err) {
  ...    // handle errors.
  return // or not, it depends.
}

... // process results
  

但这似乎非常混乱。

你会习惯的。我实际上发现它很好,代码格式良好,项目结构巧妙。

其他方式是:

  • 使用库来控制异步代码流(Async.jsStep.js等)
  • 如果您认为意大利面条式代码是混乱的,请定义一些函数来处理结果并将它们作为参数传递而不是匿名代码。

答案 1 :(得分:0)

如果你完全不喜欢写回调式的东西,你可能想尝试streamlinejs

var all_users = [];
// Get all the users for this page.
var user_ids = client.smembers("page:" + current_page_id, _);
// Now get the name of each of those users.
for (var i = 0; i < user_ids.length; i++) {
  var name = client.get('user:' + user_ids[i] + ':name', _);
  var myobj = {};
  myobj[user_ids[i]] = name;
  all_users.push(myobj);  
}
socket.broadcast('all_users', all_users);

请注意,此变体的缺点是一次只能获取一个用户名。此外,您仍应了解此代码的真正功能。

答案 2 :(得分:0)

Async是一个很棒的图书馆,你应该看看。为什么?清洁代码/流程/易于跟踪..等等

另外,请记住,在for循环之后将处理所有异步函数。在你的例子中,它可能导致错误的“i”值。使用闭包:

 for (var i = 0; i < user_ids.length; i++) { (function(i) {
 client.get('user:' + user_ids[i] + ':name', function(err, name) {
   var myobj = {};
   myobj[user_ids[i]] = name;
   all_users.push(myobj);  
   // Broadcast when we have got to the end of the loop, 
   // so all users have been added to the list - 
   // is this the best way? It seems messy.  
   if (i === (user_ids.length - 1)) {
       socket.broadcast('all_users', all_users); 
   }
 });       
})(i)}

你应该知道什么时候完成它是使用像async(我认为)那样的递归模式。它比你自己做的简单得多。

async.series({
  getMembers: function(callback) {
     client.smembers("page:" + current_page_id, callback);
  }
}, function(err, results) {
   var all_users = [];
   async.forEachSeries(results.getMembers, function(item, cb) {
    all_users.push(item);
    cb();
   }, function(err) {
      socket.broadcast('all_users', all_users); 
   });
});

此代码可能无效,但您应该能够弄清楚如何执行此操作。

步骤库也很好(我认为只有30行代码)

答案 3 :(得分:0)

  

我不明白为什么client.smembers和client.get(Redis查找)   需要成为回调,而不是简单地成为语句-它使得   生活非常复杂。

是的,所以每个人都同意回调地狱不是布宜诺斯艾利斯。在撰写本文时,回调是Node的垂死功能。不幸的是,Redis库不支持返回Promises。

但是您可能需要一个模块,如下所示:

const util = require("util");

这是一个标准库,包含在Node运行时中,并具有许多可以使用的实用程序功能,其中一个是“ promisify”: https://nodejs.org/api/util.html#util_util_promisify_original

现在,当您七年前问这个问题时, util.promisify(原始)不存在,因为它是在- v 8.0.0版本中添加的。 strong>,因此我们现在可以使用更新的答案来更新此问题。

因此 promisify 是一个函数,我们可以将其传递给client.get()之类的函数,它将返回一个具有讨厌的回调行为的新函数,而是将其包装得整洁美观。让它返回一个承诺。

因此 promisify 接受接受回调作为最后一个参数的任何函数,并使其返回一个Promise,这听起来像是您七年前想要的确切行为,而今天我们已经提供了。

const util = require("util");
client.get = util.promisify(client.get);

因此,我们将对.get()函数的引用传递给util.promisify()

这将接受您的函数,将其包装起来,因此它不执行回调,而是返回Promise。因此util.promisify()返回一个已经已承诺的新函数。

因此,您可以采用该新功能并覆盖client.get()上的现有功能。 如今,您不必为Redis查找使用回调。因此,现在您可以像这样使用async/await语法:

const cachedMembers = await client.get('user:' + user_ids[i]);

因此,我们等待解决该问题,并将其解决的所有问题分配给cachedMembers

使用ES6数组辅助方法而不是for循环,甚至可以进一步清理代码以进行更多更新。我希望这个答案对当前用户有用,否则OP已过时。