如何在Javascript中编写嵌套事务查询?

时间:2014-02-26 08:22:52

标签: javascript web-sql

我必须执行查询,获取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);

            }
        });
});
}

1 个答案:

答案 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();