2012-06-12 66 views
3

我是nodejs的新手,也许没有事件系统应该如何工作。 找不到错误。请指教。 我需要一个简单的任务 - 检查一个标签,如果它不存在,请设置新标签的关键字和信息。 问题是 - 然后我第一次运行脚本,它总是返回'键不存在'。检查redisdb钥匙 - 它创造了许多标签 这里是我的代码nodejs,redis。检查密钥是否存在,如果不存在则创建新的

for (x = 0; x < rows.length; x++) { 
    if (rows[x].term_taxonomy_id != 1) { 
     var taxonomy = findOne(rterms, rows[x].term_taxonomy_id); 
     rc.exists('tag:' + taxonomy.name, function (err, rexists) { 
      if (rexists == false) { 
       rc.incr('tags:count', function (err, id) { 
        console.log(taxonomy.name+' not exists. result ' + rexists); 
        rc.set('tag:' + taxonomy.name,id); 
        rc.hmset('tag:' + id, 
         'id', id, 
         'title',taxonomy.name, 
         'url', taxonomy.slug 
        ); 
       });//incr 
      }else{ 
       console.log(taxonomy.name+' exists!'+rexists); 
      }; 
     });//exists 
    };//ifrows 
}); 

这里是另外一个例子

var tags = [ 
    "apple", 
    "tiger", 
    "mouse", 
    "apple", 
    "apple", 
    "apple", 
    "tiger", 
    "mouse", 
    "mouse", 
]; 
var count =0; 
Object.keys(tags).forEach (function (tag) { 
    rc.get("tag:"+tags[tag],function(err,rr){ 
    console.log("get tag "+tags[tag]+" result code "+rr); 
    if (rr == null) { 
     rc.set("tag:"+tags[tag],"info",function(err,rr){ 
     count++; 
     console.log('set tag '+tags[tag]+' '+rr+' objects count '+count); 
     }); 
    }; 
    }); 
}) 

输出:

get tag apple result code null 
get tag tiger result code null 
get tag mouse result code null 
get tag apple result code null 
get tag apple result code null 
get tag apple result code null 
get tag tiger result code null 
get tag mouse result code null 
get tag mouse result code null 
set tag apple OK objects count 1 
set tag tiger OK objects count 2 
set tag mouse OK objects count 3 
set tag apple OK objects count 4 
set tag apple OK objects count 5 
set tag apple OK objects count 6 
set tag tiger OK objects count 7 
set tag mouse OK objects count 8 
set tag mouse OK objects count 9 

貌似的NodeJS执行所有“得到'命令,并且只能在'set'命令之后。所以......我明白,这都是因为异步操作。但如何使它工作?

回答

4

有这码至少有两个问题:

  • 第一个链接为Javascript封闭管理。循环的主体不会创建范围。使用Javascript,变量的范围是在功能级别,而不是块级别。您需要在循环中引入一些函数来强制创建正确的闭包。更多信息here

  • 第二个是exists和set命令之间的竞争条件。如果您有多个Redis连接存在并且在同一个键上设置了命令,那么您可能会遇到某种冲突。您应该使用setnx执行检查并在一个原子操作中进行设置,而不是使用存在和设置。

考虑到你的第二个例子,关闭问题已得到修复使用的forEach,但你仍然得到一组操作之前的所有get操作,由于语言的异步特性。

如果你真的想对所有的get和set操作进行排序(这将会慢得多),那么你可以使用一些函数式编程来实现使用递归的循环。

此程序:

var redis = require('redis') 
var rc = redis.createClient(6379, 'localhost'); 

var tags = [ 
    "apple", 
    "tiger", 
    "mouse", 
    "apple", 
    "apple", 
    "apple", 
    "tiger", 
    "mouse", 
    "mouse", 
]; 

var count = 0; 

function loop(tags) { 
    function rec_loop(tags,i) { 
    if (i >= tags.length) 
     return 
    rc.get("tag:"+tags[i],function(err,rr) { 
     console.log("get tag "+tags[i]+" result code "+rr); 
     if (rr == null) { 
      rc.set("tag:"+tags[i],"info",function(err,rr) { 
       count++; 
       console.log('set tag '+tags[i]+' '+rr+' objects count '+count); 
       rec_loop(tags,++i) 
      }) 
     } else 
      rec_loop(tags,++i) 
    }) 
    } 
    rec_loop(tags,0) 
} 

loop(tags) 

显示:

get tag apple result code null 
set tag apple OK objects count 1 
get tag tiger result code null 
set tag tiger OK objects count 2 
get tag mouse result code null 
set tag mouse OK objects count 3 
get tag apple result code info 
get tag apple result code info 
get tag apple result code info 
get tag tiger result code info 
get tag mouse result code info 
get tag mouse result code info 

注意,竞态条件仍然存在于这个例子。你应该使用setnx来实现这种检查和设置操作。

+0

谢谢。我确定程序执行流程中的问题。我做了另一个测试,并得到同样的问题。 –

+0

在我之前的回复中添加了一个示例。 –

+0

谢谢你这个伟大的例子。经过多年的线性编程后,想到异步是很困难的。 –

相关问题