2012-10-10 133 views
5

我想問這個問題,因爲我不知道我是否得到了Node.js邏輯權限Node.js&Redis;等待一個循環完成

我有一組id,我需要使用redis查詢get方法。並且在檢查某個值後(假設我檢查用給定「key」得到的對象是否具有空名稱),我將它們添加到列表中。這是我的示例代碼;

var finalList = []; 
var list = []; 
redisClient.smembers("student_list", function(err,result){ 
      list = result; //id's of students 
      console.log(result); 

      var possibleStudents = []; 


      for(var i = 0; i < list.length; i++){ 


       redisClient.get(list[i], function(err, result){ 
        if(err) 
         console.log("Error: "+err); 
        else{ 
         tempObject = JSON.parse(result); 
         if(tempObject.name != null){ 
          finalList.push(tempObject); 
         } 
        } 
       });  
      } 

    }); 
    console.log("Goes here after checking every single object"); 

但由於節點的異步性質如預期,而無需在列表檢查每一個ID它執行「在這兒... ...」。我的需要是在檢查每個id之後應用其餘的過程(在redis數據庫中映射並檢查名稱)。但我不知道該怎麼做。也許如果我可以將回調附加到for循環,並確保循環完成後我的其餘函數開始運行(我知道這是不可能的,但只是給出一個想法)?

回答

4

我會去你在你的問題建議的路線,並附上自定義回調到您的抓取功能:

function getStudentsData(callback) { 
    var setList = []; 
    var dataList = []; 

    redisClient.smembers("student_setList", function(err,result) { 
     setList = result; //id's of students 

     for(var i = 0; i < setList.length; i++) { 
      redisClient.get(setList[i], function(err, result) { 
       if(err) { 
        console.log("Error: "+err); 
       } else { 
        tempObject = JSON.parse(result); 
        if(tempObject.name != null) { 
         dataList.push(tempObject); 
        } 
       } 
      });  
     } 

     if(dataList.length == setList.length) { 
      if(typeof callback == "function") { 
       callback(dataList); 
      } 
      console.log("getStudentsData: done"); 
     } else { 
      console.log("getStudentsData: length mistmach"); 
     } 

    }); 
} 

getStudentsData(function(dataList) { 
    console.log("Goes here after checking every single object"); 
    console.log(dataList.length); 
    //More code here 
}); 

這可能是最有效的方法;或者你可以依靠一個老同學while循環,直到數據準備好:

var finalList = []; 
var list = [0]; 

redisClient.smembers("student_list", function(err,result) { 
    list = result; //id's of students 
    var possibleStudents = []; 

    for(var i = 0; i < list.length; i++) { 
     redisClient.get(list[i], function(err, result) { 
      if(err) { 
       console.log("Error: "+err); 
      } else { 
       tempObject = JSON.parse(result); 
       if(tempObject.name != null) { 
        finalList.push(tempObject); 
       } 
      } 
     });  
    } 
}); 


process.nextTick(function() { 
    if(finalList.length == list.length) { 
     //Done 
     console.log("Goes here after checking every single object"); 
     console.log(dataList.length); 
     //More code here 
    } else { 
     //Not done, keep looping 
     process.nextTick(arguments.callee); 
    } 
}); 

我們使用process.nextTick而不是實際while以確保其它請求在此期間不被堵塞;由於Javascript的單線程特性,這是首選的方式。爲了完整起見,我拋出了這一點,但前一種方法更高效,並且與node.js更合適,所以除非涉及重大重寫,否則請儘量去做。

這兩種情況都依賴異步回調,這意味着任何代碼之外的代碼仍然可能在別人完成之前運行。例如,使用我們的第一個片段:

function getStudentsData(callback) { 
    //[...] 
} 

getStudentsData(function(dataList) { 
    //[...] 
}); 

console.log("hello world"); 

這最後的console.log幾乎可以保證我們的回調傳遞給getStudentsData被炒魷魚之前運行。解決方法?爲它設計,它就是node.js的工作原理。在我們上面的例子中,很容易,我們只需要在我們的回調函數中調用console.log 只有傳遞給getStudentsData,而不是在它之外。其他場景需要的解決方案與傳統的程序編碼有些分離,但是一旦你開始瞭解它,你會發現事件驅動和非阻塞實際上是一個非常強大的功能。

+0

似乎第一個例子並不爲我工作:(參見[這](https://i.gyazo.com/129b071f39bbd1a1c491638be634b00c.png),Redis的調用是異步的。我的'results'的控制檯日誌將首先顯示,因爲它與您的示例中的邏輯完全相同,嗯。 –

1

嘗試async node.js模塊。該模塊具有異步forEach。

3

嘗試finish模塊。我創建了這個模塊來處理這個問題。它比Async更容易使用,並且性能更好。這裏有一個例子:

var finish = require("finish"); 
finish(function(async) { 
    // Any asynchronous calls within this function will be captured 
    // Just wrap each asynchronous call with function 'async' 
    ['file1', 'file2', 'file3'].forEach(function(file) { 
    async(function(done) { 
     // Your async function should use 'done' as callback, or call 'done' in its callback 
     fs.readFile(file, done); 
    }); 
    }); 
}, function(err, results) { 
    // fired after all asynchronous calls finish or as soon as an error occurs 
    console.log(results[0]);console.log(results[1]);console.log(results[2]); 
}); 
+2

應該發佈代碼示例以及鏈接。這樣,如果鏈接死掉,帖子並非無用。 – Matthew

+0

謝謝。已添加代碼示例 – Chaoran

+1

WARN:如果您的forEach'爲空,則'finish'現在扼流圈,並退出時出現「TypeError:無法讀取屬性'undefined'的屬性' 花了我一段時間來跟蹤下來;希望它可以節省別人的一些痛苦![見Github上的問題](https://github.com/chaoran/node-finish/issues/2)。 – OJFord