我是nodejs的新手,也许没有事件系统应该如何工作。 找不到bug。请指教。 我需要一个简单的任务 - 检查标签,如果它不存在,设置新密钥和有关标签的信息。 问题是 - 然后我第一次运行脚本,它总是返回'键不存在'。检查redisdb键 - 它会创建许多标签 这是我的代码
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执行所有'get'命令,并且只在'set'命令之后执行。所以......我明白,这都是因为异步操作。但是如何让它发挥作用?
答案 0 :(得分:4)
此代码中至少存在两个问题:
第一个链接到Javascript闭包管理。循环体不会创建范围。使用Javascript,变量范围是功能级别,而不是块级别。你需要在循环中引入一些函数来强制创建一个合适的闭包。更多信息here。
第二个是exists命令和set命令之间的竞争条件。如果存在多个正在运行的Redis连接并且在相同的键上设置命令,则可能会出现某种冲突。您应该使用执行检查并在一个原子操作中设置的setnx,而不是使用exists和set。
考虑到你的第二个例子,使用forEach修复了闭包问题,但是由于语言的异步性,你仍然会在设置操作之前生成所有的get操作。
如果你真的想要对所有的get和set操作进行排序(btw会慢得多),那么你可以使用一些函数式编程来实现使用递归的循环。
示例强>:
这个程序:
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来实现这种检查和设置操作。