2012-12-10 3 views
1

저는 Node.js 및 비동기 코딩을 처음 사용합니다. 노드와 함께 작동하는 중첩 for 루프와 동등한 것을 작성해야합니다. 제 질문은 nested loops asynchronusly in nodejs, next loop must start only after one gets completed에 게시 된 것과 매우 흡사합니다. 그러나 해당 게시물을 자세히 살펴본 후에도 코드를 수정할 수 없었습니다.node.js에서 비동기를 사용하기 위해 중첩 for 루프를 레코딩합니다.

저는 XML 피드로 작업하고 있습니다. '파서'는 xml2js 패키지를 사용합니다.루프는 mysql 노드 패키지를 사용하는 sql 쿼리를 제거하면 예상대로 실행되지만 SQL 쿼리를 입력하면 모든 명령이 먼저 처리되고 "완료"메시지가 출력됩니다 , 마지막 질의에 대한 항목을 반복적으로 조회하려고 할 때 쿼리가 실패합니다.

for 루프를 async.forEach 루프로 바꾸려고 시도했지만 도움이되지 않았습니다.

노드에보다 관용적 인 방식으로이를 다시 코딩하는 방법에 대한 도움이나 조언은 크게 감사하겠습니다.

감사합니다. Sixhobbits

parser.parseString(data, function (err, result) { 
    if(err) throw(err);  
    var numOrders = result['Root']['Orders'][0]['Order'].length; 
    var curr, currItem, currOrdId, items, sellersCode; 
    console.log("Logging IDs of", numOrders, "orders"); 
    // for each order 
    for (var j=0; j<numOrders; j++){ 
     //current order 
     curr = result['Root']['Orders'][0]['Order'][j];   
     currOrdId = curr['OrderId'][0]   
     items = curr['Items'][0]['Item']; 
     console.log("Order ID:", currOrdId, "--",items.length, "Items"); 
     // for each item 
     for (var k=0; k<items.length; k++){ 
      currItem = items[k]; 
      sellersCode = currItem['SellersProductCode'][0]; 
      var sqlQuery = 'select data_index, fulltext_id, cataloginventory_stock_item.product_id from catalogsearch_fulltext inner join cataloginventory_stock_item where catalogsearch_fulltext.data_index like "' + sellersCode + '|%"' + 'and cataloginventory_stock_item.item_id = catalogsearch_fulltext.product_id'; 
      var query = connection.query(sqlQuery,function(err,rows,fields){ 
       if (err) throw(err); 
       console.log(" Item ID   :",currItem['ItemId'][0]); 
       console.log(" Full Text ID  :", rows[0]['fulltext_id']); 
       console.log(" Product ID  :", rows[0]['product_id']); 
      }); 
     }//for 
    }//for 
    console.log("DONE"); 
});//parseString 

답변

4

당신은 async.forEach를 사용하여보고 바른 길에 있었다. 여기에 당신이 그것을 사용하는이 코드를 재 작업 할 방법은 다음과 같습니다의 비동기 처리가 모두 완료되면

parser.parseString(data, function (err, result) { 
    if(err) throw(err); 
    var numOrders = result['Root']['Orders'][0]['Order'].length; 
    var currOrdId, items, sellersCode; 
    console.log("Logging IDs of", numOrders, "orders"); 
    // for each order 
    async.forEach(result['Root']['Orders'][0]['Order'], function (curr, callback1) { 
     currOrdId = curr['OrderId'][0]; 
     items = curr['Items'][0]['Item']; 
     console.log("Order ID:", currOrdId, "--",items.length, "Items"); 
     async.forEach(items, function (currItem, callback2) { 
      sellersCode = currItem['SellersProductCode'][0]; 
      var sqlQuery = 'select data_index, fulltext_id, cataloginventory_stock_item.product_id from catalogsearch_fulltext inner join cataloginventory_stock_item where catalogsearch_fulltext.data_index like "' + sellersCode + '|%"' + 'and cataloginventory_stock_item.item_id = catalogsearch_fulltext.product_id'; 
      var query = connection.query(sqlQuery,function(err,rows,fields){ 
       console.log(" Item ID   :",currItem['ItemId'][0]); 
       console.log(" Full Text ID  :", rows[0]['fulltext_id']); 
       console.log(" Product ID  :", rows[0]['product_id']); 
       callback2(err); 
      }); 
     }, callback1); 
    }, function (err) { 
     console.log("DONE"); 
    }); 
});//parseString 

async.forEach의 각 반복은 콜백 매개 변수를 호출해야합니다. 이 경우 두 단계로되어있어 머리 속을 추적하는 것이 조금 더 어려워 지지만 같은 개념입니다.

+0

도와 주셔서 감사합니다! 내부 루프에 의해 생성 된 것보다 먼저 외부 루프에서 생성 된 출력을 모두 볼 수 있지만 실제로 문제가되지는 않습니다. 데이터베이스에 쿼리 한 날짜 값을 사용하여 오류가 발생했습니다. – user1789965

1

이것은 고전적인 closure-in-a-loop 문제입니다. 당신은 인수로 currItem을 전달하여 폐쇄를 중단해야합니다 나는 이것이 이전 게시물입니다 실현

for (var k=0; k<items.length; k++){ 
     currItem = items[k]; 
     sellersCode = currItem['SellersProductCode'][0]; 
     var sqlQuery = 'select data_index, fulltext_id, cataloginventory_stock_item.product_id from catalogsearch_fulltext inner join cataloginventory_stock_item where catalogsearch_fulltext.data_index like "' + sellersCode + '|%"' + 'and cataloginventory_stock_item.item_id = catalogsearch_fulltext.product_id'; 
     var query = connection.query(sqlQuery,(function(CI){ 
      return function(err,rows,fields){ 
      if (err) throw(err); 
      console.log(" Item ID   :",CI['ItemId'][0]); 
      console.log(" Full Text ID  :", rows[0]['fulltext_id']); 
      console.log(" Product ID  :", rows[0]['product_id']); 
      } 
     })(currItem)); // Break closure by passing currItem as argument 
    }//for 
+0

도움을 주셔서 감사합니다! 내부 루프에 의해 생성 된 것보다 먼저 외부 루프에서 생성 된 출력을 모두 볼 수 있지만 실제로 문제가되지는 않습니다. 데이터베이스에 쿼리 한 날짜 값을 사용하여 오류가 발생했습니다. – user1789965

0

,하지만 당신은 유용한이 기능을 찾을 수 있습니다

eachKVAsync = function(elements,userInfo,onKeyValue,ondone) { 
    var onDone = ondone; 
    var ret = null; 
    var done=false; 
    var isArray = typeof elements.forEach===$f$; 
    var keys = isArray ? null  : [], 
     values = isArray ? elements : []; 

    if (keys) { 
     for (var k in elements) { 
      keys.push(k); 
      values.push(elements[k]); 
     } 
    } 

    var aborted=false; 
    var endLoop = function (userInfo){ 
     aborted=true; 
     if (onDone) { 
      onDone(userInfo,aborted); 
      onDone = null; 
     } 
    } 


    var i = 0; 
    var iterate = function (userInfo) { 
     if (i < values.length) { 
      var ix=i; 
      i++; 
      onKeyValue((keys?keys[ix]:i),values[ix],userInfo,iterate,endLoop);   
     } else { 
      if (onDone) { 
       onDone(userInfo,aborted); 
       onDone = null; 
       return; 
      } 
     } 
    } 

    iterate(userInfo); 

}, 

사용 예를

 eachKVAsync(
      elements, { 
       aValue: 2004 
      }, 
      function onItem(key, value, info, nextItem, endLoop) { 
       if (value.isOk) { 
        info.aValue += value.total; 
        setTimeout(nextItem,1000,info); 
       } else { 
        endLoop(info); 
       } 
      }, 
      function afterLastItem(info, loopEndedEarly) { 
       if (!loopEndedEarly) { 
        console.log(info.aValue); 
       } 
      } 
     ); 
+0

이 예제 태스크에 비동기식 측면을 추가했습니다. – unsynchronized

관련 문제