このコードには少なくとも2つの問題があります:
-
最初のものはJavascriptクロージャ管理にリンクされています。ループの本体はスコープを作成しません。 Javascriptでは、変数のスコープはブロックレベルではなく、関数レベルにあります。適切なクロージャの作成を強制するには、ループ自体にいくつかの関数を導入する必要があります。詳細はこちら。
-
2つ目は、existsコマンドとsetコマンド間の競合状態です。複数のRedis接続が存在し、同じキーでコマンドを設定している場合、何らかの競合が発生する可能性があります。存在と設定を使用する代わりに、チェックと設定を1つのアトミック操作で実行するsetnxを使用する必要があります。
2番目の例を考えると、クロージャーの問題はforEachを使用して修正されていますが、言語の非同期性により、set操作の前にすべての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を使用して、この種のチェックおよびセット操作を実装することになっています。