2012-05-15 112 views
0

我從Memcached中獲得一些數據,但nodejs的異步完全沒有了我。 我想把所有的結果放到一個對象中。如何將嵌套for循環轉換爲遞歸?

這是我通常會做:

for(x = startX; x <= endX; x++) 
{ 
    for(y = startY; y <= endY; y++) 
    { 
    oData[ x + '_' + y ] = Db.get(x + '_' + y); 
    } 
} 

但我無法弄清楚如何

Db.get()功能要一個鍵和一個回調(function(error, result) {}

此只想增加x ..​​.

var onGet = function (error, result) 
{ 
    x++; 
    if(!error && result !== null) 
    { 
    oData[ x + '_' + y ] = result 
    } 
}; 

Db.get(x + '_' + y, onGet); 

回答

2

This不是一個遞歸問題,它是一個「異步問題」。你的問題是NodeJS異步訪問memcached,而你的程序風格代碼不能。所以,你需要以不同的方式思考問題。

function getMemcacheData(key, data) 
{ 
    DB.get(key, function(err, result) 
    { 
     if (err) return false; 

     data[ key ] = result; 
    }) 
} 

var oData = {}; 

for (var x = startX; x <= endX; x++) 
{ 
    for (var y = startY; y <= endY; y++) 
    { 
     var key = x + "_" + y; 
     getMemcacheData(key, oData); 
    } 
} 

這將工作,但 - 你有另一個問題,然後。你無法知道你的MemcacheD數據何時被加載到oData中,你只能坐下來等待和猜測。有辦法解決這個問題。但我最喜歡的方式是使用名爲async的庫。

隨着異步,你可以這樣做:

var syncStack = [], 
    oData = {}; 

for (var x = startX; x <= endX; x++) 
{ 
    for (var y = startY; y <= endY; y++) 
    { 
     (function(key) 
     { 
      syncStack.push(function(callback) 
      { 
       DB.get(key, function(err, result) 
       { 
        /** If you don't care about data not being loaded 
        you do this: */ 
        if (!err) 
        {    
         data[ key ] = result; 
        } 

        callback(); 

        /** If you do care, and you need to terminate if 
        you don't get all your data, do this: */ 
        if (err) 
        { 
         callback(err); 
         return false; 
        } 

        data[ key ] = result; 

        callback(); 
       })      
      }); 
     })(x + "_" + y); 
    } 
} 

async.parallel(syncStack, function(error) 
{ 
    //this is where you know that all of your memcached keys have been fetched. 
    //do whatever you want here. 

    //if you chose to use the 2nd method in the fetch call, which does 
    //"callback(error)" error here will be whatever you passed as that 
    //err argument 
}); 

這段代碼實際上做的是建立一個函數數組,其中的每一個要求的特定鍵的Db.get方法,並將結果添加到oData變量。

創建函數數組後,我們使用async庫的parallel方法,該方法接收一組函數並將它們全部並行地調用。這意味着您的代碼會將一堆請求發送到memcached以便一次性獲取您的數據。當每個功能完成時,它會調用callback函數,該函數告訴async庫,請求已完成。當它們全部完成時,async將調用您作爲調用parallel方法的第二個參數提供的回調閉包。當這個方法被調用時,你要麼知道A.出了什麼問題,並且你有錯誤可以從它恢復,B.所有的請求都完成了,你可能有或沒有你請求的所有數據(過期或過期的密鑰請求, 管他呢)。從那裏,你可以做任何你想做的事,知道你已經完成了所有你需要的鑰匙。

我希望這會有所幫助。

+1

在你的第一個代碼你排隊_all_ Memcached的請求一次,然後得到的結果,而不是連載他們一個一次。這可能是排隊請求的一個_lot_。那是故意的嗎? – Alnitak

+1

@Alnitak在這兩個片段中,我排隊所有的請求,並立即發射(幾乎)。只是它與OP代碼的最接近版本而言是有意的。例如,有更好的方法來處理它,以提高效率 - 例如,MemcacheD可以讓您通過一個請求爲大量密鑰進行多次獲取。這種方法在這裏更加適合,並且對於大量的密鑰更快速/更高效。我只是選擇儘可能保持答案儘可能接近OP的當前流量 - 所以他可以很容易地理解它(笑) –

+0

我明白了,謝謝。問題是:在'data [key] = result;'鍵總是最後一個鍵,這就成了一個參考問題,我也用我的「家釀」思路得到了:\也許我應該使用memcached而不是memcache插件,因爲它支持多件:) –

0

平行GET:

function loadPoints(cb) 
{ 
    var oData = {}; 
    for(x = startX; x <= endX; x++) 
    { 
    for(y = startY; y <= endY; y++) 
    { 
     var key = x + '_' + y;  
     num_points++; 
     Db.get(key, function(err, val) { 
     if (err) 
      return cb(err); 

     oData[key] = val; 
     num_points--; 
     if (num_points === 0) 
      cb(null, oData);   
     }); 
    } 
    } 
} 

順序得到:

function loadPoints(cb) 
{ 
    var oData = {}; 

    function loadPoint(x, y) 
    { 
     var key = x + '_' + y; 
     Db.get(key, function(err, val) { 
     if (err) 
      return cb(err); 
     oData[key] = val; 
     if (x + 1 < endX) 
      return loadPoint(x + 1, y); 
     else if (y + 1 < endY) 
      return loadPoint(startX, y+1); 
     else 
      cb(null, oData); 
     }); 
    } 
    loadPoint(startX, startY); 
}