Node.js &Redis;等待循环完成 [英] Node.js & Redis; Waiting for a loop to finish

查看:39
本文介绍了Node.js &Redis;等待循环完成的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I would like to ask this question, because I'm not sure if I got the Node.js logic right

我有一组 ID,需要使用 redis 的 get 方法进行查询.在检查了某个值之后(假设我正在检查使用给定键"获得的对象是否具有空名称),我将它们添加到列表中.这是我的示例代码;

I have a set of id's that I need to query using redis' get method. And after checking a certain value(let's say that im checking whether the object I get with given "key" has a null name), I add them to a list. Here is my example code;

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 的异步性质,它在不检查列表中的每个 id 的情况下执行Goes here...".我的需要是在检查每个 id 后应用其余的程序(在 redis db 中映射并检查名称).但我不知道该怎么做.也许如果我可以将回调附加到 for 循环并确保我的其余函数在循环完成后开始运行(我知道这是不可能的,但只是提供一个想法)?

But as expected due to the async nature of Node, without checking every single id in the list it executes the "Goes here...". My need is to apply the rest of procedures after every id is checked(mapping in redis db and checking the name). But I do not know how to do it. Maybe if I can attach callback to the for loop and assure the rest of my functions start to run after loop is finished(i know it's impossible but just to give an idea)?

推荐答案

我会按照您在问题中建议的路线并将自定义回调附加到您的获取函数:

I would go the route you suggest in your question and attach a custom callback to your fetching 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 循环,直到数据准备好:

That's probably the most efficient method; alternatively you could rely on an old school while loop until the data is ready:

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,因此除非涉及重大重写,否则请继续使用.

We use process.nextTick instead of an actual while to make sure other requests are not blocked in the meantime; due to the single threaded nature of Javascript this is the preferred way. I'm throwing this in for the sake of completeness, but the former method is more efficient and fits better with node.js, so go for it unless a major rewrite is involved.

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

It's worth nothing that both cases rely on async callbacks, which means any code outside it can still potentially run before others are done. E.g., using our first snippet:

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

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

console.log("hello world");

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

That last console.log is almost guaranteed to run before our callback passed to getStudentsData gets fired. Workaround? Design for it, it's just how node.js works. In our case above it's easy, we just would call console.log only in our callback passed to getStudentsData and not outside it. Other scenarios require solutions that depart a bit more from traditional procedural coding, but once you get your head around it you'll find being event-driven and non-blocking is actually a pretty powerful feature.

这篇关于Node.js &amp;Redis;等待循环完成的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆