JavaScript中的WebSQL查询在for循环内。如何知道何时完成?

8
我猜我有一个相对简单的问题,但我一直在打转,即使Google也没有给我一个可行的答案。
基本上,我正在尝试复制存储在WebSQL本地的一些记录。 复制不是问题,但我需要知道何时完成所有复制操作,然后我的程序才能继续执行。
WebSQL调用是异步的,因此通常情况下唯一的方法是使用回调函数来处理这些事情。但是,由于查询是在for循环内完成的,因此我不能使用回调函数,因为如下所示,它将在第一个完成的查询处触发。
代码如下:
function copyRecords(old_parent_id, new_parent_id, callback){
    var db = openDatabase('test', '1.0', 'test', 50 * 1024 * 1024);
    db.transaction(function (tx) {
        tx.executeSql('SELECT * FROM table WHERE parent_id = ?', [old_parent_id], function(tx, results){
            for(var i = 0; i < results.rows.length; i++){
                db.transaction(function (tx2) {
                    tx2.executeSql('INSERT INTO table (name, parent_id) VALUES (?, ?)', [results.rows.item(i).name, new_parent_id], callback);
                })
            }
        });
    });
}

我也尝试在i==results.rows.length时调用回调函数,但这并不能确保所有查询都已完成。

我猜你们中的一些人之前也遇到过这个问题,希望能帮忙解决并确保只有在for循环完成后才调用回调函数。

提前感谢。


将内部事务从循环中移出结果,使得INSERT的循环完全在事务内部,这样做是否可行? - Stan
2个回答

8

通常的做法是使用递归异步回调来处理每个单独的记录,而不是使用for循环。

当还有更多的记录时,异步回调会调用自身。当没有记录时,它可以调用您提供的回调函数。

下面的代码将替换您的内部回调处理程序的内容:

(function nextRecord() {
    var row = results.rows.shift();
    if (row) {
        db.transaction(function (tx2) {
            tx2.executeSql('INSERT INTO table (name, parent_id) VALUES (?, ?)',
                [row.item(i).name, new_parent_id], nextRecord);
       });
    } else {
        callback();
    }
})();

谢谢你的回答!我从来没有想过使用递归函数! - user1749815
谢谢您的建议,但似乎Web SQL结果不支持shift()函数,因为它不是一个数组。所以我不得不手动递增计数器,这样就可以了! - Matthieu

2
这最好通过计算“回调”函数的执行次数来完成,只有在达到结果集的完整数量后才继续进行。
以下是您的代码进行修改后的版本:
function copyRecords(old_parent_id, new_parent_id, callback){
    var db = openDatabase('test', '1.0', 'test', 50 * 1024 * 1024);
    db.transaction(function (tx) {
        tx.executeSql('SELECT * FROM table WHERE parent_id = ?', [old_parent_id], function(tx, results){
            if (results.rows.length == 0) 
                callback(); // don't forget this case!
            else {
                var nbrInserted = 0; // This will keep track of how many have been inserted
                for(var i = 0; i < results.rows.length; i++){
                    db.transaction(function (tx2) {
                        tx2.executeSql('INSERT INTO table (name, parent_id) VALUES (?, ?)', [results.rows.item(i).name, new_parent_id], function() {
                            ++nbrInserted; // increment this for every insert
                            if (nbrInserted == results.rows.length) // check if complete
                                callback(); // Do your callback.
                        });
                    });
                }
            }
        });
    });
}

关于我,我发现WebSQL的异步API有点麻烦,并且由于WebSQL数据库可能会消失(标准已经被放弃),我建议每个人都转换到SequelSphere。它是一个跨所有浏览器和所有平台工作的HTML5 / JavaScript关系型数据库。它还将数据存储在localStorage中,使其具有WebSQL的所有好处,而不会遇到所有麻烦。
如果上述解决方案对您不起作用,请告诉我。
祝好运!
约翰...

你真的应该声明你对SequelSphere的兴趣。 - Alnitak
好的,你说得很对。请原谅我,我与SequelSphere有联系,无法忍住要做推广。 - John Fowler
p.s. 异步回调并不繁琐 - 请查看我的答案以了解如何 正确地 进行操作! - Alnitak
附言:异步编程非常繁琐,但也非常必要。这只是我的个人意见。我非常喜欢你的答案,但如果我理解正确的话,当从选择中没有返回行时,你的答案会出错。 - John Fowler
糟糕!...碰巧...问题已解决。 - John Fowler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接