2012-10-10 3 views
5

Node.js 로직이 올바른지 확실하지 않기 때문에이 질문을하고 싶습니다.Node.js & Redis; 루프가 끝날 때까지 기다리는 중

나는 redis를 사용하여 쿼리해야하는 ID 집합을 가지고 있습니다. 'get 방법. 그리고 특정 값을 확인한 후에 (주어진 "key"를 가진 객체가 null 이름을 가지는지 확인하고 있다고 가정 해 봅시다) 목록에 추가합니다. 다음은 예제 코드입니다. 목록에있는 모든 단일 ID를 확인하지 않고, 노드의 비동기 특성으로 인해 예상대로

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를 사용하는 것이 더 효율적이며 더 적합합니다. 따라서 주요 재 작성이 포함되어 있지 않으면이 방법을 사용하십시오.

두 경우 모두 비동기 콜백에 의존 할 가치가 없습니다. 즉, 비동기 콜백을 사용하면 다른 코드가 실행되기 전에 잠재적으로 실행될 수 있습니다. 예를 들어, 첫 번째 조각을 사용하여 : 마지막 CONSOLE.LOG 거의 getStudentsData에 전달 우리의 콜백 해고되기 전에 실행을 보장

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

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

console.log("hello world"); 

있다. 해결 방법은 무엇입니까? 이를 위해 디자인하면 node.j가 어떻게 작동하는지 알 수 있습니다. 우리의 경우 위의 경우 쉽게 호출 할 수 있습니다. 우리는 console.log를 이라고하고, getStudentsData에 전달 된 콜백에서는 밖에 있고 그 외부에는 없습니다. 다른 시나리오에서는 기존의 절차 적 코딩과 조금 더 다른 솔루션을 필요로하지만, 일단 주위를 둘러 보면 이벤트 중심적이고 비 차단이 실제로는 매우 강력한 기능이라는 것을 알게 될 것입니다.

+0

먼저 예 :(나를 위해 작동하지 않는 것 [이] (https://i.gyazo.com/129b071f39bbd1a1c491638be634b00c.png)의 레디 스 호출이 비동기 참조하십시오. 내 결과의 콘솔 로그가 첫 번째로 표시 될 것입니다. 예를 들어, 예제와 똑같은 논리가 있습니다. –

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 : 정의되지 않은 속성 '킥오프'를 읽을 수 없습니다. 아래로, 그것은 누군가 다른 고통을 저장 희망![Github의 문제보기] (https://github.com/chaoran/node-finish/issues/2). – OJFord

관련 문제