2012-10-10 10 views
5

を終了するのを待っています方法。そして特定の値をチェックした後(与えられた "key"で取得したオブジェクトがヌル名を持っているかどうかを確認しています)、それらをリストに追加します。ここに私のコード例があります。リスト内のすべての単一のIDをチェックせずに、ノードの非同期な性質のために期待されるようNode.js&Redis;私はこの質問をお願いしたいと思い、私はわからないので、私はNode.jsのロジック私は私が手のRedisを使用してクエリを実行する必要があるIDのセットを持って右</p> <p>を得た場合、ループは、

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がチェックされた後に残りの手順を適用することです(redis dbでのマッピングと名前の確認)。しかし、私はそれを行う方法を知らない。たぶん、コールバックを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); 
    } 
}); 

我々はその間にブロックされていないことを確認、他の要求を作成する代わりに、実際のwhileprocess.nextTickを使用します。 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の呼び出しは非同期であるザ・が。 –

1

try 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

警告: 'forEach'配列が空の場合、' finish'は現在チョークしていて、 "TypeError:未定義のプロパティ 'kickoff'を読み取れません" それは他の誰かにいくつかの痛みを保存することを願っています[Githubの問題を参照](https://github.com/chaoran/node-finish/issues/2)。 – OJFord

関連する問題

 関連する問題