node/redis和回调的控制流问题?

xytpbqjk  于 5个月前  发布在  Redis
关注(0)|答案(4)|浏览(45)

请问我可以问一些关于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之前已经执行了所有的查找?


eblbsuwk

eblbsuwk1#

我不明白为什么client.smembersclient.get(Redis查找)需要是回调而不是简单的语句--这让生活变得非常复杂。
这就是Node。(我敢肯定,这个主题在这里讨论了足够多的时间,看看其他问题,它肯定在那里)
如何确保在调用socket.broadcast之前已执行了所有查找?
这就是回调函数中err的含义。这有点像Node的标准-回调函数中的第一个参数是error object(如果一切正常,则为null)。因此,只需使用类似以下的内容来确保没有错误发生:

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

... // process results

字符串
但这看起来很乱。
你会习惯的。我发现当代码的格式很好,项目的结构很巧妙的时候,这是很好的。
其他方式有:

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

mefy6pfw2#

如果你完全不喜欢写回调风格的东西,你可能想试试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);

字符串
请注意,这种变体的缺点是一次只能获取一个用户名。此外,您仍然应该了解此代码的实际用途。

jhdbpxl9

jhdbpxl93#

Async是一个很棒的库,你应该看看。为什么?干净的代码/过程/易于跟踪..等
另外,请记住,所有的functional函数都将在for循环后处理。在functional中,它可能会导致错误的“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)}

字符串
你应该做的是知道什么时候它完成了是使用一个递归模式,就像dec(我认为)做。这是非常简单的,然后自己做。

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行代码)

zengzsys

zengzsys4#

我不明白为什么client.smembers和client.get(Redis查找)需要回调而不是简单的语句-这让生活变得非常复杂。
是的,所以每个人都同意回调地狱是 no bueno。在撰写本文时,回调是Node的一个垂死的功能。不幸的是,Redis库没有对返回Promises的原生支持。
但是有一个模块你可以像这样要求:
第一个月
这是一个标准库,包含在Node运行时中,有一堆我们可以使用的实用函数,其中一个是“promisify”:https://nodejs.org/api/util.html#util_util_promisify_original
当然,当你七年前问这个问题时,util.promisify(original)并不存在,因为它是在-v 8.0.0中添加的,所以我们现在可以用更新的答案更新这个问题。
所以
promisify
是一个函数,我们可以传递给它一个像client.get()这样的函数,它将返回一个新的函数,该函数接受讨厌的回调行为,并将其 Package 得很好,很整洁,使其返回Promise。
所以promisify接受任何接受回调作为最后一个参数的函数,并使其返回Promise,听起来这正是你七年前想要的行为,我们今天可以提供。

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

字符串
因此,我们将.get()函数的引用传递给util.promisify()
这会获取你的函数,将其 Package 起来,这样它就不会实现一个回调,而是返回一个Promise。所以util.promisify()返回一个新的函数,这个函数已经被 promisified 了。
所以你可以使用这个新函数并覆盖client.get()上现有的函数。现在,你不必使用回调来进行Redis查找。所以现在你可以像这样使用async/await语法:
const cachedMembers = await client.get('user:' + user_ids[i]);
所以我们等待这个问题被解决,无论它解决了什么,都会被分配给cachedMembers
代码可以通过使用ES6数组帮助器方法而不是for循环来进一步清理以进行更新。我希望这个答案对当前用户有用,否则OP就过时了。

相关问题