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

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

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

要testing,只需打开http://jsfiddle.net/Tk9rv/embedded/result/在IOS上的移动Safari浏览器,加载时不要触摸设备。 您将看到正在生成的debugging消息列表,如下所示:

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' [...] 

现在,重新加载页面,并加载时,随机滚动和点击。 您将看到一些“即将插入…”的信息丢失。

 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' [...] 

这是因为transactionCallback被完全跳过了! 但为什么? 而为什么successCallback火而不是errorCallback?

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

我觉得在这里有一个类似的问题HTML5的Web SQL事务缺less在行动但没有任何解决scheme或提示。

有任何想法吗? 我卡住了……谢谢!

我们的testing表明,只要键盘正在显示,这种行为也会发生,并会阻止onblur或onfocus事件中的事务(尽pipe不是onkey {down | up | press})。 使用setTimeout会导致可怕的性能问题。 我们发现即使事务callback没有被调用,也会触发.transaction()成功的callback,所以想出了这个方法对我们来说很好:

 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; } 

这段代码检查事务callback是否在成功处理器中被触发,如果没有的话,给它一个机会。

Web Workers和OpenDatabaseSync在我的网站上解决了同样的问题。 除了Web工作人员不支持iOS4.x和Android,所以我们可以在iOS5上为那些和Web工作人员实现旧的方式。

下面的基本示例使用一个循环在每次插入后执行一次500次的单次插入操作。 最后,查询返回表中的行数。 现在我们可以看到,即使滚动很多,交易也不会被跳过。

此示例旨在让您testing在iPhone或iPad上插入期间的滚动恢复能力。

需要两页,一个html页面和一个单独的javascript文件给worker。 所以对于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> 

和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; }