`

使用web sql适配local storage存储

 
阅读更多

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的支持,我个人表示不信任。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics