IPAD的localstorage上限只有5M,不够用,现在想用websql替代,最初设计又没考虑到回调的方式,结果代码修改很多――我个人十分不喜欢html5 websql/file api的调用方式,phonegap的插件使用callback指针,这点还可以理解,至于纯js为什么要设计成这样,不解――抱怨下,下面贴下代码
?
/** * Begin class defination XDB : Web sql辅助方法 */ var XDB = { db: null, init: function(dbName, version, dbDisplayName, size){ if(window.openDatabase) this.db = openDatabase(dbName, version, dbDisplayName, size); }, exe: function(sql, args, callback){ if(!this.db){ X.log('Web sql not support!'); return; } this.db.transaction(function(tx){ if(!sql.contains('t_key_val')) X.log('Web sql exe : ' + sql + ' || ' + (args ? args.join(',') : 'null')); tx.executeSql(sql, args, function(tx, results){ if(callback) callback(results); }, function(tx, err){ // SQLError X.log('Web sql execute error: ' + err.message); }); }); }, exeSqlLl: function(sqlLl, pre, suf){ if(!this.db){ X.log('Web sql not support!'); return; } pre = pre || ''; suf = suf || ''; this.db.transaction(function(tx){ X.log('Web sql exe : ' + sqlLl.length); var savedLog = false; var i = 0; for (; i < sqlLl.length; i++){ var sql = sqlLl[i]; if(sql.trim()){ sql = pre + sql + suf; tx.executeSql(sql, null, null, function(tx, err){ // SQLError X.log('Web sql execute error: ' + err.message); if(!savedLog){ X.logDb('Web sql execute error: ' + err.message); X.logDb('Web sql sql: ' + sql); savedLog = true; } }); } } }); }, trans: function(fn){ if(!this.db){ X.log('Web sql not support!'); return; } this.db.transaction(fn); }, // crud add: function(data, table){ var keys = _.keys(data); var str1 = keys.join(','); var str2 = _.map(keys, function(it){return '?';}).join(','); var sql = 'insert into {0} ({1}) values ({2})'; sql = sql.format(table, str1, str2); var args = _.values(data); this.exe(sql, args) }, del: function(data, table){ var keys = _.keys(data); var strClause = _.map(keys, function(it){ return it + ' = ?'; }).join(' and '); var sql = 'delete from {0} where {1}'; sql = sql.format(table, strClause); var args = _.values(data); this.exe(sql, args) }, update: function(data, dataClause, table){ var strSet = _.map(_.keys(data), function(it){ return it + ' = ?'; }).join(', '); var argsSet = _.values(data); var strClause = _.map(_.keys(dataClause), function(it){ return it + ' = ?'; }).join(' and '); var argsClause = _.values(dataClause); var sql = 'update {0} set {1} where {2}'; sql = sql.format(table, strSet, strClause); this.exe(sql, argsSet.merge(argsClause)) }, queryItem: function(sql, args, callback){ this.exe(sql, args, function(results){ if(callback){ if(results.rows.length > 0){ var item = results.rows.item(0); if(!sql.contains('t_key_val')) X.log('Query resultset item : ' + JSON.stringify(item)); callback(item); }else{ callback(null); } } }); }, query: function(sql, args, callback){ this.exe(sql, args, function(results){ X.log('Query resultset size : ' + results.rows.length); if(callback) callback(results.rows); }); }, queryAndMap: function(sql, args, callback, callback2){ this.query(sql, args, function(rows){ if(callback){ var i = 0; for (; i < rows.length; i++){ var record = rows.item(i); callback(record, i); } } if(callback2) callback2(rows); }); }, pi: function(sql, args, cp, npp, callback){ var pager = new XPager(cp, npp, 0); var countSql = 'select count(1) as rowCount from ({0})'.format(sql); var subSql = 'select * from ({0}) limit {1}, {2}'.format(sql, pager.getStart(), npp); var _this = this; this.query(countSql, args, function(rows){ pager.rowCount = rows.item(0)['rowCount']; _this.query(subSql, args, function(rows){ if(callback) callback(pager, rows); }); }); }, piAndMap: function(sql, args, cp, npp, callback, callback2){ this.pi(sql, args, cp, npp, function(pager, rows){ if(callback){ var i = 0; for (; i < rows.length; i++){ var record = rows.item(i); callback(record, i); } if(callback2) callback2(pager); } }); }, dump : '' }; // HTML5本地存储只能存字符串 // 当本地存储受限时候,使用db var XLocal = { storage: null, keyGlobal: null, init: function(key){ if(window.localStorage){ this.storage = window.localStorage; if(key){ this.keyGlobal = key; } }else{ X.log('Web localStorage api not support!'); } }, clear: function(){ if(!this.storage){ X.log('Web localStorage api not support!'); return; } if(this.keyGlobal){ this.storage.removeItem(this.keyGlobal); }else{ this.storage.clear(); } }, get: function(key, unpack){ if(!this.storage){ X.log('Web localStorage api not support!'); return; } if(!this.keyGlobal){ var str = this.storage[key]; if(!str || 'undefined' == str || 'null' == str) return null if(unpack) str = LzwCN.unpack(str); return JSON.parse(str); }else{ var str = this.storage[this.keyGlobal]; if(str){ var item = JSON.parse(str); return item ? item[key] : null; } } }, put: function(key, val, pack){ if(!this.storage){ X.log('Web localStorage api not support!'); return; } X.log('Web localStorage put ' + key); if(!this.keyGlobal){ // 先删除,ipad localstorage不删除会有问题? // http://stackoverflow.com/questions/5887326/is-localstorage-reliable-on-an-ipad this.remove(key); var str = JSON.stringify(val); if(pack) str = LzwCN.pack(str); this.storage[key] = str; }else{ this.remove(key); var item = {}; var str = this.storage[this.keyGlobal]; if(str) item = JSON.parse(str); item[key] = val; this.storage[this.keyGlobal] = JSON.stringify(item); } }, remove: function(key){ if(!this.storage){ X.log('Web localStorage api not support!'); return; } X.log('Web localStorage remove ' + key); if(!this.keyGlobal){ this.storage.removeItem(key); }else{ var str = this.storage[this.keyGlobal]; if(str){ var item = JSON.parse(str); if(item){ item[key] = null; this.storage[this.keyGlobal] = JSON.stringify(item); } } } }, dump: '' }; var XLocalDB = { init: function(){ XDB.exe('create table if not exists t_key_val(k varchar,v varchar)'); }, clear: function(){ var sql = 'delete from t_key_val'; setTimeout(function(){ XDB.exe(sql); }, 100); }, /* XLocalDB.clear() XLocalDB.put('y', {a: 'xx'}) XLocalDB.get('y', function(item){ X.log(item); }); */ get: function(key, fn){ var sql = 'select v from t_key_val where k = ?'; var sqlArgs = [key]; XDB.queryItem(sql, sqlArgs, function(item){ if(!item){ if(fn) fn(null); }else{ var src = item.v; if(src){ src = LzwCN.unpack(src); var val = JSON.parse(src); if(fn) fn(val); }else{ if(fn) fn(null); } } }); }, put: function(key, val){ X.log('Web DB put ' + key); var src = JSON.stringify(val); src = LzwCN.pack(src); var item = {k: key, v: src}; setTimeout(function(){ XDB.add(item, 't_key_val'); }, 100); }, remove: function(key){ X.log('Web DB remove ' + key); var item = {k: key}; setTimeout(function(){ XDB.del(item, 't_key_val'); }, 100); }, dump: '' };
?
注意:调用XDB方法时候,加上setTimeout,这点算是个hack,在使用web sql之前,还想到一个思路是进行字符串压缩,效果也很好,压缩率在50%以上,js的压缩类,我也贴下:
var LzwCN = {}; LzwCN.compress = function(text){ var result = []; for(var n = 0; n < text.length; n++){ var c = text.charCodeAt(n); if (c < 128){ result.push(String.fromCharCode(c)); }else if (c > 127 && c < 2048){ result.push(String.fromCharCode((c >> 6) | 192)); result.push(String.fromCharCode((c & 63) | 128)); }else{ result.push(String.fromCharCode((c >> 12) | 224)); result.push(String.fromCharCode(((c >> 6) & 63) | 128)); result.push(String.fromCharCode((c & 63) | 128)); } } return result.join(''); }; LzwCN.decompress = function(text){ var result = []; var i = 0, c1 = 0, c2 = 0, c3 = 0; while(i < text.length){ c1 = text.charCodeAt(i); if (c1 < 128){ result.push(String.fromCharCode(c1)); i++; }else if (c1 > 191 && c1 < 224){ c2 = text.charCodeAt(i + 1); result.push(String.fromCharCode(((c1 & 31) << 6) | (c2 & 63))); i += 2; }else{ c2 = text.charCodeAt(i + 1); c3 = text.charCodeAt(i + 2); result.push(String.fromCharCode(((c1 & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63))); i += 3; } } return result.join(''); }; LzwCN.pack = function(str){ var result = []; var rstr = this.compress(str); var i = 0, size = 0, xstr = '', chars = 256, dict = []; for(i = 0; i < chars; i++){ dict[String(i)] = i; } var splitted = rstr.split(''); var buffer = []; var current = ''; for(i = 0; i <= splitted.length; i++){ current = new String(splitted[i]); xstr = (buffer.length == 0) ? String(current.charCodeAt(0)) : (buffer.join('-') + '-' + String(current.charCodeAt(0))); if (dict[xstr] !== undefined){ buffer.push(current.charCodeAt(0)); }else{ result.push(String.fromCharCode(dict[buffer.join('-')])); dict[xstr] = chars; chars++; buffer = [current.charCodeAt(0)]; } } return result.join(''); }; LzwCN.unpack = function(str){ var i, chars = 256, dict = []; for(i = 0; i < chars; i++){ dict[i] = String.fromCharCode(i); } var original = new String(str); var splitted = original.split(''); var buffer = ''; var chain = ''; var result = []; for(i = 0; i < splitted.length; i++){ var code = original.charCodeAt(i); var current = dict[code]; if(buffer == ''){ buffer = current; result.push(current); }else{ if(code <= 255){ result.push(current); chain = buffer + current; dict[chars] = chain; chars++; buffer = current; }else{ chain = dict[code]; if(chain == null){ chain = buffer + buffer.slice(0, 1); } result.push(chain); dict[chars] = buffer + chain.slice(0, 1); chars++; buffer = chain; } } } return this.decompress(result.join('')); };
?
最后一句:苹果在ios设备上对html5的支持,我个人表示不信任。