2012-06-12 85 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

謝謝你這個偉大的例子。經過多年的線性編程後,想到異步是很困難的。 –

相關問題