2014-02-26 3 views
0

나는 쿼리를 실행하고, id를 얻고, for 루프로 3 개의 쿼리를 더 실행해야한다. 이 함수에서는 변수를 연결합니다. 그러나 중첩 된 쿼리 내의 값은 추가되지 않습니다. 이 문제에 대해 더 나은 해결책을 찾도록 도와주세요.Javascript에서 중첩 된 트랜잭션 쿼리를 코딩하는 방법은 무엇입니까?

db.transaction(function (tx) { 
    tx.executeSql('SELECT * FROM contacts ', [], 
     function (tx, results) { 
      for (var i = 0; i < results.rows.length; i++) { 
       var row = results.rows.item(i); 
       var ds = ""; 
       ds += ""; 
       ds += "BEGIN:VCARD\n" 
       ds += "VERSION:2.1\n" 
       ds += "N:" + row.last_name + ";" + row.first_name + ";" + row.middle_name + ";" + row.prefix + "\n" 
       ds += "FN:" + row.prefix + " " + row.first_name + " " + row.middle_name + " " + row.last_name + "\n" 
       ds += "ORG:" + row.company + "\n" 
       ds += "TITLE:" + row.title + "\n" 

       // append phone numbers 
       tx.executeSql("Select * from contact_details where contact_id='" + row._id + "' and data_type='1' ", [], 
        function (tx, resu) { 
         if (resu.length != 0) { 

          for (b = 0; b < resu.rows.length; b++) { 
           var myrow = resu.rows.item(b); 

           if (myrow.contact_type == "Home LandLine") 
            ds += "TEL;HOME;VOICE:" + myrow.contact_data + "\n" 
           if (myrow.contact_type == "Home Mobile") 
            ds += "TEL;HOME;CELL:" + myrow.contact_data + "\n" 
           if (myrow.contact_type == "Home Fax") 
            ds += "TEL;HOME;FAX:" + myrow.contact_data + "\n" 

           if (myrow.contact_type == "Work LandLine") 
            ds += "TEL;WORK;VOICE:" + myrow.contact_data + "\n" 
           if (myrow.contact_type == "Work Mobile") 
            ds += "TEL;WORK;CELL:" + myrow.contact_data + "\n" 
           if (myrow.contact_type == "Work Fax") 
            ds += "TEL;WORK;FAX:" + myrow.contact_data + "\n" 
          } 

         } 
        }) 


       //ds+=$("#hidexport").text(); 
       // append emails 
       tx.executeSql("Select * from contact_details where contact_id='" + row._id + "' and data_type='2' ", [], 
        function (tx, resuy) { 
         for (y = 0; y < resuy.rows.length; y++) { 
          var myrowy = resuy.rows.item(y); 
          ds += "EMAIL;INTERNET:" + myrowy.contact_data + "\n" 
         } 
        }); 

       // append websites 
       tx.executeSql("Select * from contact_details where contact_id='" + row._id + "' and data_type='3' ", [], 
        function (tx, resuz) { 
         for (z = 0; z < resuz.rows.length; z++) { 
          var myrowz = resuz.rows.item(z); 
          ds += "URL:" + myrowz.contact_data + "\n" 
         } 
        }); 

       // append address 
       ds += "ADR;WORK:" + row.company_add_1 + ";" + row.company_add_2 + ";" + row.company_city + ";" + row.company_region + ";" + row.company_state 
       ds += ";" + row.company_zip + ";" + row.company_country + "\n" 
       ds += "LABEL;WORK;ENCODING=QUOTED-PRINTABLE:" + row.company_add_1 + ";" + row.company_add_2 + ";" + row.company_city + ";" 
       ds += row.company_region + ";" + row.company_state + ";" + row.company_zip + "=0D=0" + row.company_country + "\n" 

       console.log(ds); 

      } 
     }); 
}); 
} 

답변

4

SQL 쿼리가 비동기입니다. 즉, 기능이 종료 된 후 얼마 지나지 않아 완료됩니다. 3 개의 비동기 연산을 차례로 실행하려면 수행 한 것처럼 순차적으로 코드를 작성할 수 없습니다. 모두 한 번에 그들을 시작하고 그들은 언젠가 나중에 모두 끝납니다.

또한 함수가 즉시 완료되었지만 나중에 비동기 작업이 완료되기 때문에 결과를 함수에서 반환 할 수 없습니다.

개념적으로 가장 쉬운 방법은 (처음에는 우아하지 않지만 개념적으로 단순함) 첫 번째 작업을 시작하고 첫 번째 작업의 완료 기능에서 결과를 수집 한 다음 완료 기능에서 두 번째 작업을 시작하십시오. 그런 다음 자체 완료 기능을 갖게되며 완료 기능에서 세 번째 작업을 시작하고 완료 기능에서 모든 결과를 수집하게됩니다. 그런 다음 (세 번째 중첩 완료 함수 내부에서) 결과를 가져 와서 일부 외부 함수를 호출하고 결과를 전달할 수 있습니다. 최종 완성 기능 내에서만 결과를 얻고이를 사용할 수 있습니다.

다음은이 개념의 모습입니다 : 좀 더 우아한 여러 비동기 작업을 직렬화하는 다른 많은 방법이 있습니다

tx.executeSql("Select ...", function(tx, resuz) { 
    ds += ...; 
    tx.executeSql("Select ...", function(tx, resuz) { 
     ds += ...; 
     tx.executeSql("Select ...", function(tx, resuz) { 
      ds += ...; 
      console.log(ds); 
      processResult(ds); 
     }); 
    }); 
}); 

. 약속을 사용할 수 있고 작업 대기열을 사용할 수 있습니다.

쿼리를 병렬로 실행할 수있는 경우 세 가지 쿼리를 동시에 실행하고 결과를 수집 한 다음 결과를 모두 처리하면 더 빨리 실행할 수 있습니다 그들 중 실행이 완료됩니다. 개념적으로 다음과 같이 보이 :

var results = [null, null, null]; 
var resultCntr = results.length; 

function checkResults() { 
    if (resultCntr === 0) { 
     // all results are in now 
     ds += results[0] + results[1] + results[2]; 
     console.log(ds); 
     processResult(ds); 
    } 
} 

tx.executeSql("Select ...", function(tx, resuz) { 
    results[0] = ...; 
    --resultCntr; 
    checkResults(); 
}); 
tx.executeSql("Select ...", function(tx, resuz) { 
    results[1] = ...; 
    --resultCntr; 
    checkResults(); 
}); 
tx.executeSql("Select ...", function(tx, resuz) { 
    results[2] = ...; 
    --resultCntr; 
    checkResults(); 
}); 

당신의 작업이 유사하다면, 그들은 아마도 몇 가지 공통 코드보다는 간단한 복사/붙여 넣기 세 번에 고려 될 수있다. 비동기 작업의 무리에 for 루프에 해당하는 작업을 수행하려는 경우


, 그럼 당신은 for 루프를 사용할 수 없습니다. 대신, 당신은 당신이 이전 반복의 완료 핸들러에서 루프의 다음 반복을 개념적으로 같은 것을 할 필요가 :

var rowCntr = 0; 
var ds = ""; 
function processRow() { 
    var row = results.rows.item(rowCntr); 
    tx.executeSql("Select ...", function(tx, resuz) { 
     ds += ... 
     ++rowCntr; 
     if (rowCntr < results.rows.length) { 
      processRow(); 
     } else { 
      // all rows done now 
      // do whatever you want to do when you've collected the data for all the rows 
     } 
    }); 
} 
// process the first row 
processRow();  
+0

이 솔루션에 대한 선생님 감사합니다, 나는 그것이 작동 최초의 솔루션을 시도했다 – Bhavana