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

Node.js&;Redis;等待循环完成,node.js,asynchronous,redis,Node.js,Asynchronous,Redis,我想问这个问题,因为我不确定Node.js逻辑是否正确 我有一组id,需要使用redis的get方法进行查询。在检查了某个值之后(假设我正在检查给定“key”的对象是否有空名称),我将它们添加到列表中。下面是我的示例代码 var finalList = []; var list = []; redisClient.smembers("student_list", function(err,result){ list = result; //id's of students

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

我有一组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");
var finalList=[];
var列表=[];
redisClient.smembers(“学生列表”,函数(err,result){
list=result;//学生id
控制台日志(结果);
var可能学生=[];
对于(变量i=0;i

但正如预期的那样,由于节点的异步性质,在不检查列表中的每个id的情况下,它会执行“Goes here…”。我需要在检查每个id之后应用其余的过程(在redis db中映射并检查名称)。但我不知道怎么做。如果我可以将回调附加到for循环,并确保循环完成后我的其余函数开始运行(我知道这是不可能的,但只是给出一个想法)?

尝试node.js模块。该模块具有异步forEach。

我将按照您在问题中建议的路线,为您的获取函数附加一个自定义回调:

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
});
我们使用
process.nextTick
而不是实际的
while
来确保其他请求在此期间不会被阻止;由于Javascript的单线程特性,这是首选的方法。为了完整起见,我加入了这个方法,但是前一种方法更有效,并且更适合node.js,因此,除非涉及到重大重写,否则请继续使用它

这两种情况都依赖于异步回调,这一点毫无意义,这意味着它之外的任何代码都可能在其他代码完成之前运行。例如,使用我们的第一个片段:

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

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

console.log("hello world");
最后一个console.log几乎可以保证在调用传递给getStudentsData的回调之前运行。解决办法?为之设计,这就是node.js的工作方式。在我们上面的例子中,很简单,我们只需要在传递给getStudentsData的回调中调用console.log,而不是在它之外。其他场景需要的解决方案与传统的过程性编码稍有不同,但一旦你了解了这一点,你就会发现事件驱动和非阻塞实际上是一个非常强大的功能。

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

应该张贴代码的样本以及链接。那样的话,如果链接失效,帖子也不是没有用的。谢谢。添加了代码示例。警告:finish如果您forEach的数组为空,并且以“TypeError:无法读取未定义的属性“kickoff”退出,则当前阻塞。我花了一段时间才找到它;希望它能帮别人省去一些痛苦@奥利福的问题已经解决了。谢谢你的报道。这是天赐之物。。。哦,我的上帝。谢谢第一个示例似乎对我不起作用:(.请看,redis调用是异步的。我的
结果的控制台日志将首先显示,因为它与您的示例中的逻辑完全相同,hmmm。
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]);
});