如何使WebSQL查询同步?

时间:2013-02-10 14:23:31

标签: javascript sqlite asynchronous synchronous web-sql

考虑:

var globalvar;

function viewyearmain() {
  db.transaction(function (tx) 
  {
    tx.executeSql('SELECT * FROM BUDGET WHERE holdingtype="month"', [], function (tx, results) 
    {
       var len = results.rows.length;
       msg = len;
       globalvar = msg;
    }, null);

  });

  if (globalvar>0)
  {
    alert("ROWS FOUND");
  }
  else
  {
    alert("ROWS NOT FOUND");
  }
}

问题是ROWS NOT FOUND出现是因为到达if语句时事务尚未完成。

6 个答案:

答案 0 :(得分:6)

异步回调不是同步的,无论你想要它多少。

所有依赖于结果的代码移动到回调中:

var globalvar;

function viewyearmain() {
  db.transaction(function (tx) 
  {
    tx.executeSql('SELECT * FROM BUDGET WHERE holdingtype="month"', [], function (tx, results) 
    {
       var len = results.rows.length;
       msg = len;
       globalvar = msg;
       if (globalvar>0)
       {
         alert("ROWS FOUND");
       }
       else
       {
         alert("ROWS NOT FOUND");
       }
    }, null);

  });
}

或者,将其移至第二个函数,并从回调中调用它。

答案 1 :(得分:0)

据我所知,WebSQL不支持同步SQL语句。这通常是一件好事,因为您不希望处理SQL来中断或冻结您的用户界面。因此,CL。的答案为处理查询结果提供了正确的异步机制。

但是,如果您确实需要同步SQL查询,请查看WebSQL替代方案:SequelSphere - An HTML5 / JavaScript SQL Relational Database

它是100%JavaScript,因此它可以在任何浏览器和任何平台上运行。此外,它将其数据存储在IndexedDB或LocalStorage中。它还包含WebSQL不具备的许多功能:JSON集成,更改跟踪器,用户定义的SQL函数,同步SQL处理等。由于WebSQL标准已被弃用,我认为这是一个很好的选择。

完全披露:我喜欢WebSQL,但我与SequelSphere结婚了。

答案 2 :(得分:0)

现在有点晚了,但是为了它的价值...你不能使调用同步,但你可以通过使用Async这样的库来简化你的代码。这似乎有点矫枉过正,但如果你需要连续执行3或4个语句,它可以使你的代码更容易阅读。

async.waterfall([
    function(callback){
        db.transaction(function (tx) {
            tx.executeSql('SELECT * FROM BUDGET WHERE holdingtype="month"', [], 
                function (tx, results) {
                    var len = results.rows.length;
                    callback(null, len)
                }, 
                function(){
                    callback("An error occurred when reading data");
                }
            }); 
       });
    },
    function(len, callback){
        // Now do something with the length.
        console.log("The length is: " + len);
    }
]);

答案 3 :(得分:0)

我已经迟了几年了,但考虑到这个问题从未得到直接回答,我想我会把我的两分钱投入,并且还会添加一些建议!

首先,如果您正在阅读本文,那么您可能不应该使用WebSQL。它已经deprecated支持IndexedDB,此时它是W3C标准轨道上唯一的数据库。

如果出于某种原因,你打算使用WebSQL,并且你可以没有其异步API提供的好处(其中一些在John Fowler的答案中提到),那么你应该知道它的规范也定义了一个synchronous API

所以是的,有一种方法可以同步执行WebSQL中的语句,前提是您正在开发的浏览器已经实现了同步API。

如果您不介意处理与同步接口一样简单的异步接口,请查看BakedGoods

有了它,执行查询就像:

bakedGoods.getAll({
    filter: "valueObj.holdingType === 'month'",
    storageTypes: ["webSQL"],

    //Contains database configuration data and operation preferences
    options: optionsObj,

    complete: function(byStorageTypeResultDataObj, byStorageTypeErrorObj){}
});

其简单的界面和无与伦比的存储设施支持是以缺乏对某些特定于存储设施的配置的支持为代价的。例如,它不支持在具有多列主键的WebSQL表中进行存储操作。

因此,如果您大量使用这些类型的功能,您可能需要查看其他地方。

哦,为了完全透明,BakedGoods真的由你自己维护:)。

答案 4 :(得分:0)

不太同步-但这是一个开始。

创建一个帮助器函数以从Promise中执行查询

const executeSql = (query, params) => new Promise ( (resolve, reject) => {
  tx.executeSql(query, params, resolve, reject);
};

然后从异步功能运行时,可以使用'await'关键字

const myFunc = async () => {
   let result = await executeSql("SELECT * FROM BUDGET WHERE holdingtype=?", ["month"]);
}

但是,一旦Promise实现,对象可能会取消引用,因此交易结果可能会出现问题。

const executeSql = (query, params) => new Promise ( (resolve, reject) => {
    tx.executeSql(query, params, 
        (tx, results) => {
            var items = [];
            if(results.rows.length)
            {
                var max = results.rows.length;
                for (var x = 0; x < max; x++) items.push(results.rows.item(x))
            }
            resolve(items)
        }, reject)
    })

答案 5 :(得分:0)

如今,您可以利用async / await并做出如下承诺:

async function alertResult() {
  const rows = await viewyearmain();
  if (rows.length) {
    alert("ROWS FOUND");
  } else {
    alert("ROWS NOT FOUND");
  }
}

function viewyearmain() {
  return new Promise(resolve => {
    db.transaction(function(tx) {
      tx.executeSql("SELECT * FROM BUDGET WHERE holdingtype = ?;", ["month"], function(tx, result) {
        resolve(result.rows);
      }, null);
    });
  });
}