javascript - WebSQL 事务不会在 JS 回调函数中运行

标签 javascript jquery cordova

我正在使用 PhoneGap 和 jQuery Mobile。我试图从远程位置获取一些 JSON 数据,然后用它填充本地 WebSQL 数据库。这是我的 JS 函数:

function getLocations() {

    var tx = window.openDatabase('csdistroloc', '1.0', 'Distro DB', 1000000);
    tx.transaction(function(tx) {
        tx.executeSql('DROP TABLE IF EXISTS locations'); //this line works!
        tx.executeSql('CREATE TABLE IF NOT EXISTS locations (id, name, address, postalcode, phone, category)'); //this line works!

        $.ajax({
          url: "http://mydomain.com/api.php",
          dataType: 'json',
          data: { action: "getlocations" },
          success: function(data) {
            tx.executeSql("INSERT INTO locations (id, name, address, postalcode, phone, category) VALUES (2,'cheese','232','seven',5,6)"); //this line produces an error
        }});

    }, dberror, dbsuccess);

}

运行上面的函数在上面提到的行中给我一个错误“INVALID_STATE_ERR: DOM Exception 11”。当我实际尝试使用返回的 JSON 数据插入数据时,它会做同样的事情。我还尝试了 $.getJSON 技术,得到了完全相同的结果。

如有任何建议,我们将不胜感激!

最佳答案

尽管 accepted answer是正确的,我想对其进行扩展,因为我遇到了同样的问题,并且该答案没有说明为什么它不像 OP 那样工作。

当您在 Web SQL 中创建事务时,事务处理仅在 there are any statements queued up in the transaction 时保持事件状态。 .一旦事务中的语句管道干涸,引擎就会关闭(提交)事务。这个想法是当 function(tx) { ... } 回调运行时,

  1. 它执行它需要执行的所有语句。 executeSql 是异步的,因此即使语句尚未执行,它也会立即返回。
  2. 它将控制返回给 Web SQL 引擎。

此时引擎注意到有语句在排队,并在关闭事务之前运行它们直到完成。在你的情况下,会发生什么:

  1. 你调用 executeSql 两次来排队两个语句。
  2. 您通过 ajax 请求一些东西。
  3. 你回来了

引擎运行它排队的两个语句。 ajax 请求也在异步运行,但它必须访问速度较慢的网络,因此它可能尚未完成。此时,语句队列为空,Web SQL 引擎决定是时候提交并关闭事务了!它无法知道稍后还会有另一个声明!当 ajax 调用返回并尝试执行 INSERT INTO locations 时,为时已晚,事务已经关闭。

已接受的答案建议的解决方案有效:不要在 ajax 回调中使用相同的事务,而是创建一个新事务。不幸的是,它有一个陷阱,你会期望使用 2 个事务而不是 1 个事务:操作不再是原子的。这对您的申请可能重要,也可能不重要。

如果事务的原子性对您很重要,您唯一的 2 个资源是:

  • 在 ajax 回调内的一个事务中执行所有操作(所有 3 个语句)。

    这是我推荐的。我认为等到 ajax 请求完成后再创建表很可能符合您的应用程序要求。

  • 同步执行ajax请求as explained here .

    我不推荐这样做。 JavaScript 中的异步编程是一件的事情。

顺便说一下,我在 Promises 的上下文中遇到了这个问题,代码看起来像这样:

// XXX don't do this, it doesn't work!
db.transaction(function(tx) {
    new Promise(function(resolve, reject) {
        tx.executeSql(
            "SELECT some stuff FROM table ....", [],
            function(tx, result) {
                // extract the data that are needed for
                // the next step
                var answer = result.rows.item( .... ).some_column;
                resolve(answer);
            }
        )
    }).then(function(answer) {
        tx.executeSql(
            "UPDATE something else",
            // The answer from the previous query is a parameter to this one
            [ ... , answer, .... ]
        )
    });
});

问题在于,对于 promises,链式 .then() 子句不会在原始 promise 解析后立即运行。它只是排队等候稍后执行,很像 ajax 请求。唯一的区别是,与缓慢的 ajax 请求不同,.then() 子句几乎立即运行。但是“几乎”还不够好:它可能会或可能不会运行得足够快以在事务关闭之前将下一个 SQL 语句滑入队列;因此,代码可能会或可能不会产生无效状态错误,具体取决于时间安排和/或浏览器实现。

太糟糕了:Promise 在 SQL 事务中使用会很有用。上面的伪示例可以很容易地在没有 promise 的情况下重写,但是一些用例可以极大地利用许多 .then() 链以及诸如 Promise.all 这可以确保整个 SQL 语句集合以任何顺序运行,但都在其他语句之前完成。

关于javascript - WebSQL 事务不会在 JS 回调函数中运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9953324/

相关文章:

javascript - 根据当前填充颜色更改注释填充

用于动态添加内容的 jquery 事件

javascript - 如何通过存在于 page1.aspx 中的 javascript 访问,存在于 page2.aspx 中的隐藏字段在两个框架的框架集中

html - http-equiv 值 'Content-Security-Policy' 到底有什么作用?

javascript - 使用计算结果自动填充输入字段

javascript - lang 选项在 WordPress 中不起作用

javascript - 如何将现有回调 API 转换为 Promise?

javascript - 检测到多个事件,其中应该只有一个

javascript - cordovaDialogs没有返回值

android - PouchDB 数据在应用程序退出后被删除