使用uni-app开发,客户端本地数据存储选择sqllite
uni-app官网 (dcloud.io)
HTML5+ API Reference (html5plus.org)
异步执行的代码一般都有回调,在外层方法中创建自己的回调函数,通过回调实现业务操作,曲折实现“同步执行”的逻辑。
由于业务需要,在app客户端要进行本地数据存储。本人常年开发java,面向对象理念深入人心,于是需要在合适的位置写一个dbUtils.js的工具类,提供数据库增删改查的方法,返回执行结果。但是在调试过程中发现sqllite操作数据库的方法是异步的,所以按照传统的返回值方式无法取得正确结果。
初始思路:先定义返回结果变量,操作完成后返回结果
// 此方法行不通! export function executeSql(sql){ let result = false; // 打开数据库 plus.sqlite.openDatabase({ // 数据库名称 name: 'xxxxx', // 数据库文件路径 path: '_doc/xxxxx.db', // 打开数据库成功 success: function(e){ result = true; }, fail:function(e){ console.log(e); } }); if (result) { // 执行sql plus.sqlite.executeSql({ name:'xxxxx', sql: sql, success(){ result = true; }, fail(e) { console.log(e); } }); } // 关闭数据库 plus.sqlite.closeDatabase({name: 'xxxxx'}); return result; }
通过调试发现方法永远返回false,在执行plus.sqllite.xxx时,js继续执行了,没有等待,导致执行是数据库已经关闭,后来我把执行sql写在打开数据库的回调中,关闭数据库写在执行sql的回调中,但只能解决数据库操作部分的执行顺序正确,返回值仍然不对。
这时我想暴力解决这个异步问题,产生了一个天真大胆的想法,在异步执行时阻断程序执行,监听异步操作是否执行完成
let executeFinished = false; ......各种数据库操作,完成时赋值executeFinished = true; while(true) { if (executeFinished) { break; } } ......后续操作
然后发现程序卡在while(true)那里了,永远进不去数据库操作回调方法,executeFinished自然永远不会变。
经过查阅资料,发现js是单线程的,那么while(true)一直循环程序就阻断了。js中的异步处理只是合适的时机去执行,底层并不是并行的。
最后,通过给公共方法传回调事件,曲折解决了sqllite的异步问题
/** * 增/删/改 sql执行 * @param {Object} sql * @param {Object} callback */ export function executeSql(sql, callback){ let result = {}; // 打开数据库 plus.sqlite.openDatabase({ // 数据库名称 name: 'xxxxx', // 数据库文件路径 path: '_doc/xxxxx.db', // 打开数据库成功 success: function(e){ plus.sqlite.executeSql({ name:'xxxxx', sql: sql, success(){ result.success = true; closeDatabase(); callback(result); }, fail(e) { result.success = false; result.data = e; closeDatabase(); callback(result); } }); }, fail:function(e){ result.success = false; result.data = e; closeDatabase(); callback(result); } }); } /** * 数据库查询select * @param {Object} sql * @param {Object} callback */ export function selectSql(sql, callback){ let result = {}; // 打开数据库 plus.sqlite.openDatabase({ // 数据库名称 name: 'xxxxx', // 数据库文件路径 path: '_doc/xxxxx.db', // 打开数据库成功 success: function(e){ plus.sqlite.selectSql({ name:'xxxxx', sql: sql, success(data){ result.success = true; result.data = data; closeDatabase(); callback(result); }, fail(e) { result.success = false; result.data = e; closeDatabase(); callback(result); } }); }, fail:function(e){ result.success = false; result.data = e; closeDatabase(); callback(result); } }); } /** * 关闭数据库 */ function closeDatabase() { plus.sqlite.closeDatabase({name: 'xxxxx'}); }
import { executeSql } from '@/common/db/dbUtils.js';
let sql = "insert into xxxxxxxxxx"; executeSql(sql, function(result) { if (result.success) { // 业务操作 } else { // 执行失败操作 } });