在IOS中触发触摸时,HTML5 Web SQL事务会跳过而不会出错

Tob*_*tta 11 javascript sql iphone html5 ios

我在IOS设备上进行数据库事务时遇到问题.如果用户没有触摸手机,一切都按预期工作.如果用户点击/滚动/触摸屏幕,一些事务直接调用其successCallback,而不调用实际的事务回调.

这里的简化示例:http://jsfiddle.net/Tk9rv/

要测试,只需在IOS上的移动Safari中打开http://jsfiddle.net/Tk9rv/embedded/result/,并且在加载时不要触摸设备.您将看到生成的调试消息列表,如下所示:

database is running
table will be cleared
store method called for '10'.
about to insert '10'.
transaction successful for '10'
store method called for '9'.
about to insert '9'.
transaction successful for '9'
store method called for '8'.
about to insert '8'.
transaction successful for '8'
[...]
Run Code Online (Sandbox Code Playgroud)

现在,重新加载页面并在加载时,滚动并随机点击.您将看到一些"即将插入..."消息丢失.

database is running
table will be cleared
store method called for '10'.
about to insert '10'.
transaction successful for '10'
store method called for '9'.
about to insert '9'.
transaction successful for '9'
store method called for '8'.
transaction successful for '8' <-- WHERE IS MY "about to insert '8'." ???
store method called for '7'.
about to insert '7'.
transaction successful for '7'
[...]
Run Code Online (Sandbox Code Playgroud)

这是因为完全跳过了transactionCallback!但为什么?为什么successCallback会触发而不是errorCallback?

[这是一个简化的例子,请不要告诉我不要这样做setTimeout的东西.在现实世界中,有数据被加载异步,然后插入... :)]

我认为这里有一个类似的问题HTML5 Web SQL事务Missing In Action但是也没有解决方案或提示.

有任何想法吗?我被困了......谢谢!

小智 9

我们的测试显示,只要键盘显示,这种行为也会发生,并且会阻止onblur或onfocus事件中的事务(尽管不是onkey {down | up | press}).使用setTimeout会导致严重的性能问题.我们发现即使没有调用事务回调,也会触发.transaction()成功回调,所以想出了适合我们的方法:

var oldOpenDatabase = window.openDatabase;
window.openDatabase = function() {
    var db = oldOpenDatabase.apply(window, arguments);

    var oldTrans = db.transaction;
    db.transaction = function(callback, err, suc) {
        var db = this;
        var params = arguments;
        var hasRun = false;
        oldTrans.call(db, function(tx){
            hasRun = true; callback(tx);
        }, err||function(){}, function(tx) {
            if(hasRun){
                if (suc != undefined)
                    suc(tx); 
                return;
            }
            else {
                oldTrans.apply(db, params);
            }
        });
    }

    return db;
}
Run Code Online (Sandbox Code Playgroud)

此代码检查事务回调是否已在成功处理程序中触发,如果没有,则为其提供另一次机会.


aja*_*yel 0

Web Workers 和 OpenDatabaseSync 修复了我网站上的相同问题。除了 iOS4.x 和 Android 上不支持 Web Worker 之外,因此我们可以在 iOS5 上为这些和 Web Worker 实现旧方法。

下面的非常基本的示例使用循环执行单个插入,并在每次插入后写入屏幕 500 次。最后进行查询以返回表中的行数。现在我们可以看到,即使进行大量滚动,事务也不会被跳过。

此示例旨在让您可以测试在 iPhone 或 iPad 上插入时滚动的弹性。

需要两个页面,一个 html 页面和一个供工作人员使用的单独的 javascript 文件。所以对于html页面来说;

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport"/>
    <meta name="apple-mobile-web-app-capable" content="yes" />
    <meta name="apple-mobile-web-app-status-bar-style" content="black" />
    <title></title>
    <script src="../scripts/jquery-1.6.2.min.js" type="text/javascript"></script>
    <style type="text/css">
    body
    {
    background-color:Black;
    }
    .number
    {
    color:#00FF00;
    font-family:Courier New;
    font-size:12pt;
    }
    button
    {
    position:fixed;
    right:5px;
    top:5px;
    padding:15px;
    }
    </style>
    <script type="text/javascript">
    var worker;
    $(document).ready(function () {

        worker = new Worker('worker1.js');
        worker.addEventListener('message', function (e) {
        $("#test").html(new Date().toLocaleTimeString() + " " + e.data.message + "<BR/>" + $("#test").html());
        if (e.data.complete == true) {
            worker.terminate();
        }
        }, false);
    });

    function stop() {
        worker.terminate();
    }
    </script>

</head>
<body>
    <form id="form1" onsubmit="return false">
    <div id="test" class="number">
    <button onclick="stop()">Stop</button>
    </div>
    </form>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)

和worker1.js;

var wdb = {};
wdb.db = openDatabaseSync('test', '1.0', 'DB test', 1024);

doQuery("CREATE TABLE IF NOT EXISTS test(abc INTEGER PRIMARY KEY);");
doQuery("DELETE FROM test"); // optional

for (var i = 0; i < 500; i++) {
    doQuery("INSERT INTO test(abc) VALUES( " + i + " );");
    postMessage({ message: "Inserted " + i.toString(), complete: false });
}

var summary= doQuery("SELECT COUNT(*) AS Total FROM test;");
postMessage({ message: "Found " + summary.item(0).Total.toString() + " rows", complete: true });

function doQuery(sql) {
    wdb.db.transaction(function (tx) {
    rs = tx.executeSql(sql, []);
    });
    return rs.rows;
}
Run Code Online (Sandbox Code Playgroud)