Node.js&Redis; 等待一个循环完成

我想问这个问题,因为我不确定是否得到了Node.js逻辑

我有一组id,我需要使用redis'get方法来查询。 并检查一个特定的值(假设检查是否我给与“关键”的对象具有空名称),我将它们添加到列表中。 这是我的示例代码;

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"); 

但正如预期的那样,由于Node的asynchronous性质,没有检查列表中的每一个ID它执行“去这里…”。 我的需要是在检查每个id之后应用其余的过程(在redis数据库中映射并检查名称)。 但我不知道该怎么做。 也许如果我可以将callback附加到for循环,并确保循环完成后我的其他function开始运行(我知道这是不可能的,但只是给一个想法)?

我会走你在你的问题build议的路线,并附加一个自定义callback您的抓取function:

 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,所以除非涉及到重大的重写,否则不要这样做。

这两种情况都不依赖于asynchronouscallback,这意味着它之外的任何代码仍然可能在别人完成之前运行。 例如,使用我们的第一个片段:

 function getStudentsData(callback) { //[...] } getStudentsData(function(dataList) { //[...] }); console.log("hello world"); 

最后的console.log几乎可以保证在我们传递给getStudentsData的callback被触发之前运行。 解决方法? devise它,就是node.js的工作原理。 在我们上面的例子中,很容易,我们只是在调用console.log的时候, 在调用getStudentsData的时候调用它。 其他情况下,需要的解决scheme与传统的程序编码有些分离,但是一旦你开始了解它,你会发现事件驱动和非阻塞实际上是一个非常强大的function。

尝试完成模块。 我创build了这个模块来处理这个问题。 它比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]); }); 

尝试node.js的asynchronous模块 该模块具有asynchronousforEach。