我必须执行查询,获取id并使用for循环执行3次查询。在这个函数中我连接变量。但是嵌套查询中的值不会被追加。请帮我找到解决这个问题的更好方法。
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);
}
});
});
}
答案 0 :(得分:4)
您的Sql查询是异步的。这意味着他们在你的功能退出很久之后很久就完成了一段时间。如果你想一个接一个地运行三个异步操作,那么你就不能像你那样按顺序编写它们。所有这一切都是立即启动它们,然后它们都会在稍后完成。
此外,您无法从函数返回结果,因为您的函数会立即完成,但异步操作会在稍后完成。
修复此问题的概念上最简单的方法(不是超级优雅,但在概念上简单)是启动第一个操作,在第一个操作的完成函数中,您从中收集结果,然后在该完成函数中,您启动第二次行动。然后它将拥有它自己的完成功能,并在该完成功能中启动第三个操作并在其完成功能中,您现在将收集所有结果。然后,您可以(从第三个嵌套的完成函数内部)获取结果并调用一些外部函数并将结果传递给它。只有从最终完成功能中获得结果才能使用它们。
以下是概念上的概念:
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);
});
});
});
还有许多其他方法可以序列化更多优雅的多个异步操作。你可以使用promises,你可以使用任务队列等......
如果查询可以并行运行,则可以通过一次启动所有三个查询,收集结果,然后在完成所有查询完成后处理结果来更快地运行它们。概念上看起来像这样:
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();