6

Node.js のロジックが正しいかどうかわからないので、この質問をしたいと思います。

redis の get メソッドを使用してクエリを実行する必要がある ID のセットがあります。そして、特定の値をチェックした後(たとえば、指定された「キー」で取得したオブジェクトの名前がnullかどうかをチェックしているとしましょう)、それらをリストに追加します。これが私のコード例です。

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 をチェックせずに、「Goes here...」を実行します。私の必要性は、すべてのIDがチェックされた後に残りの手順を適用することです(redis dbでのマッピングと名前のチェック)。しかし、私はそれを行う方法がわかりません。コールバックを for ループにアタッチし、ループが終了した後に残りの関数が確実に実行されるようにできれば (不可能だとはわかっていますが、アイデアを提供するだけです)。

4

3 に答える 3

5

私はあなたがあなたの質問で提案するルートに行き、あなたのフェッチング関数にカスタムコールバックを添付します:

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に、実際の代わりに使用します。whileJavascriptのシングルスレッドの性質により、これが推奨される方法です。完全を期すためにこれを投入しますが、前者の方法の方が効率的で、node.jsとの適合性が高いため、大幅な書き換えが必要でない限り、これを選択してください。

どちらの場合も非同期コールバックに依存していることは何の価値もありません。つまり、それ以外のコードは、他のコードが実行される前に実行される可能性があります。たとえば、最初のスニペットを使用します。

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

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

console.log("hello world");

その最後のconsole.logは、getStudentsDataに渡されたコールバックが発生する前に実行されることがほぼ保証されています。回避策?そのための設計、それはnode.jsがどのように機能するかです。上記の場合は簡単です。getStudentsDataに渡されたコールバックでのみconsole.logを呼び出し、その外部では呼び出しません。他のシナリオでは、従来の手続き型コーディングから少し離れたソリューションが必要ですが、頭を悩ませると、イベント駆動型であり、非ブロッキングであることが実際には非常に強力な機能であることがわかります。

于 2012-10-11T13:10:33.740 に答える
3

モジュールを終了してみてください。この問題に対処するために、このモジュールを作成しました。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]);
});
于 2013-01-29T17:44:24.027 に答える
1

node.js のasyncモジュールを試してください。そのモジュールには非同期 forEach があります。

于 2012-10-10T13:48:12.783 に答える