Web SQL Database的异步机制
2017-03-16 01:46
381 查看
概述
Web SQL Database是一个主要基于异步的实现。其原理是, 发起SQL语句命令后, 不待结果传回, 立即将程序流程控制权转交给下一语句。SQL语句执行完毕后, 单独线程再调用回调函数, 返回查询结果。什么意思呢? 看看下面的伪码:
var id = executeSql("SELECT ID FROM tableA"); executeSql("SELECT * FROM tableB WHERE ID = ?", [id]);
我们需要先从表A中取出一个ID值并赋值于id, 接着, 希望使用这个id来进行下一步的查询。
由于异步工作机制, 这段代码是无法工作的。当第一个executeSql()语句发起后, 还未等结果出来, 就立即执行第二条executeSql()语句了。此时, id的状态是undefined, 当然无法进行正确的查询。
正确的做法应是将第二条语句放在一个回调函数中执行, 这样可确保只有等第一个查询结果出来后才执行第二条语句。
executeSql("SELECT ID FROM tableA", function(resultSet) { var id = resultSet.rows.item(0).ID; executeSql("SELECT * FROM tableB WHERE ID = ?", [id]) });
这样, 就造成了嵌套会越来越长。且由于再加上很容易混淆的transaction()函数, 编写这样的代码又臭又长, 即难看,又容易出错。
本文通过简要地说明transaction()及executeSql()各个函数参数的作用, 从最简单的需求开始, 渐渐细化为功能较为齐全且代码结构清晰的一个解决办法。
关于transaction及readTransaction
void transaction(in SQLTransactionCallback callback, in optional SQLTransactionErrorCallback errorCallback, in optional SQLVoidCallback successCallback); interface SQLTransactionCallback { void handleEvent(in SQLTransaction transaction); }; interface SQLTransactionErrorCallback { void handleEvent(in SQLError error); }; interface SQLVoidCallback { void handleEvent(); };
第一个SQLTransactionCallback用于使用所传入的tx。第二个可显示错误信息。第三个是当处理完整个transaction时, 统一回调callback函数。
关于executeSql函数
void executeSql(in DOMString sqlStatement, in optional ObjectArray arguments, in optional SQLStatementCallback callback, in optional SQLStatementErrorCallback errorCallback); interface SQLStatementCallback { void handleEvent(in SQLTransaction transaction, in SQLResultSet resultSet); }; interface SQLStatementErrorCallback { boolean handleEvent(in SQLTransaction transaction, in SQLError error); };
由于执行Sql语句时, 有时需要返回查询结果, 因此SQLStatementCallback有一SQLResultSet的形参。可在这里将查询结果改为程序所需的各种形式。
结合使用transaction及executeSql
一个transaction可一并使用多个executeSql。因此, 可将多个Sql语句放在一个transaction执行完毕后, 整合多个Sql语句的结果, 再将该结果作为参数来调用transaction的successCallback。这样做,可较完美地利用并发机制。db.transaction( function(tx) {}, // use tx function(error) {}, // handle error if any function() {} // this callback will be called if the transaction is committed );
再进一步:
db.transaction( function(tx) { tx.executeSql(); tx.executeSql(); ... }, function(error) {}, // handle error if any function() {} // call this callback if the transaction is committed );
现在,如何将tx.executeSql()的结果传给最后的函数里呢? 毕竟该函数没有形参。很简单, db.transaction()虽然很长, 但它毕竟只是一个函数。在此函数前声明一个变量, 用于保存tx.executeSql()的结果, 这样, 第三个回调函数也可以使用该结果了。
var result = {}; db.transaction( function(tx) { tx.executeSql( "SELECT ID FROM ... WHERE ID = ?", [1], function(tx, resultSet) { result.id = resultSet.rows.item(0).ID; // save the selected ID in result.id }, function(tx, error) { console.log(error.code + error.message); } ); tx.executeSql(); ... }, function(error) {}, // handle error if any function() {} // call this callback if the transaction is committed );
tx.executeSql()共有4个参数。在第三个参数(该参数为函数)中, resultSet是执行查询完毕后所传回的结果, 可在这个函数中将查询结果保存至前面所声明的变量。第四个函数参数, 可用于即时检查执行Sql语句可能出现的错误, 如, Sql语句语法错误, 或往数据库中插入数据时, 出现了违反了键值唯一的错误,等等。这一步不要轻易省略, 可大大缩短调试时间。
第二个tx.executeSql()可灵活地执行另一相关的Sql语句。例如, 查询并返回多项记录。
var result = {}; db.transaction( function(tx) { tx.executeSql( "SELECT ID FROM ... WHERE ID = ?", [1], function(tx, resultSet) { result.id = resultSet.rows.item(0).ID; // save the selected ID in result.id }, function(tx, error) { console.log(error.code + error.message); } ); tx.executeSql( "SELECT * FROM customer", [], function(tx, resultSet) { result.resultSet = resultSet; // save the whole resultSet in result.resultSet }, function(tx, error) { console.log(error.code + error.message); } ); ... }, function(error) {}, // handle error if any function() {} // call this callback if the transaction is committed );
如果事务执行过程中有任一错误, 就会将error传回db.transaction()的第三个函数参数。
var result = {}; db.transaction( function(tx) { tx.executeSql( "SELECT ID FROM ... WHERE ID = ?", [1], function(tx, resultSet) { result.id = resultSet.rows.item(0).ID; // save the selected ID in result.id }, function(tx, error) { console.log(error.code + ", " + error.message); } ); tx.executeSql( "SELECT * FROM customer", [], function(tx, resultSet) { result.resultSet = resultSet; // save the whole resultSet in result.resultSet }, function(tx, error) { console.log(error.code + error.message); } ); ... }, function(error) { console.log("transaction error = " + error.code + ", " + error.message); }, function() {} // call this callback if the transaction is committed );
最后一步, 可在db.transaction()的第四个函数参数中使用上面声明的变量了。
var result = {}; db.transaction( function(tx) { tx.executeSql( "SELECT ID FROM ... WHERE ID = ?", [1], function(tx, resultSet) { result.id = resultSet.rows.item(0).ID; // save the selected ID in result.id }, function(tx, error) { console.log(error.code + ", " + error.message); } ); tx.executeSql( "SELECT * FROM customer", [], function(tx, resultSet) { result.resultSet = resultSet; // save the whole resultSet in result.resultSet }, function(tx, error) { console.log(error.code + error.message); } ); ... }, function(error) { console.log("transaction error = " + error.code + ", " + error.message); }, function() { console.log(result.id); console.log(result.resultSet); } );
当然, 如果嫌这个函数过长, 可将第四个函数参数分解为另一个单独的函数。
function doQueris() { var result = {}; db.transaction( function(tx) { tx.executeSql( "SELECT ID FROM ... WHERE ID = ?", [1], function(tx, resultSet) { result.id = resultSet.rows.item(0).ID; // save the selected ID in result.id }, function(tx, error) { console.log(error.code + ", " + error.message); } ); tx.executeSql( "SELECT * FROM customer", [], function(tx, resultSet) { result.resultSet = resultSet; // save the whole resultSet in result.resultSet }, function(tx, error) { console.log(error.code + error.message); } ); ... }, function(error) { console.log("transaction error = " + error.code + ", " + error.message); }, function() { onQuerriesFinished(result); } ); } function onQueriesFinished(result) { console.log(result.id); console.log(result.resultSet); }
这里有两个函数: doQueris()及onQueriesFinished()。变量result成为doQueris()的局部变量。在doQueris()函数的事务执行完毕后, 通过传递result局部变量给onQueriesFinished()这个回调函数, 从而实现了将查询结果在不同的函数之间进行传递的效果。
最后, 只需简单地发起查询命令:
doQueris();
所有问题都会得到完美、有序的解决。
相关文章推荐
- HTML5客户端数据存储机制Web Storage和Web SQL Database
- Android与WebView的同步和异步訪问机制
- HTML 5 Web SQL Database初探
- HTML5 Web SQL Database 数据库的使用方法
- HTML5 Web Database 数据库的SQL语句的使用方法
- html5 Web SQL Database 之事务处理函数transaction与executeSQL解析
- Web Sql Database
- 【C#】对异步请求处理程序IHttpAsyncHandler的理解和分享一个易用性封装 【手记】走近科学之为什么明明实现了IEnumerable<T>的类型却不能调用LINQ扩展方法 【手记】手机网页弹出层后屏蔽底层的滑动响应 【手记】ASP.NET提示“未能创建类型”处理 【Web】一个非常简单的移动web消息框 【手记】解决EXCEL跑SQL遇“查询无法运行或数据库表无法打开...”
- Web SQL Database的基本使用方法
- Web SQL Database
- HTML 5 Web SQL Database小结
- HTML5本地存储——Web SQL Database
- html5 使用web SQL database简单实例
- Web SQL Database
- html5 本地数据库-Web SQL Database操作类
- Web SQL Database
- 通过Web SQL Database将…
- HTML5本地存储——Web SQL Database
- HTML5 Web SQL Database 数据库的使用方法
- Web SQL Database