技术头条 - 一个快速在微博传播文章的方式     搜索本站
您现在的位置首页 --> CSS/HTML --> HTML5实战之本地存储(2)

HTML5实战之本地存储(2)

浏览:1993次  出处信息

    本文介绍Tab之间的操作同步的实现,所谓操作同步是指将用户在某个Tab窗口中的操作同步到所有其他同一站点得Tab中。例如IM窗口的操作(打开、最大化、最小化、关闭、设置等),由于很多用户会在多个Tab之间切换,而IM在每个页面中都存在,因此对于数据同步的要求是比较高的,以前的做法是使用服务器方式来同步,即所有操作都向服务器发请求,然后广播,Tab收到消息后再响应。缺点是比较浪费资源,另外延时也比较严重。

实现

    在具体的实现上,只是给封装的Storage添加了一个sync接口,格式如下:

/*
	跨页面同步指定的函数
	@param {function}	func		需要同步执行的函数(不允许重名,函数参数必须为string类型,否则参数无法同步)
	@param {Object}		context		返回的函数执行时的上下文
	@param {Boolean}	onlySync	是否只执行同步,为true时不执行原函数而只执行同步操作
	@return {function}  当执行新的函数时将会通过本地存储进行同步操作
*/
function sync( func, context, onlySync ){ }

    sync接口会接收一个需要同步的函数A,并对A进行处理,返回函数B。当执行函数B的时候会选择性的执行函数A(有得情况下是已经执行了A,只需要同步,这时是不需要再次执行A函数的),然后把执行B时的参数通过本地存储方式同步到其他Tab。

Key的生成

    这里比较关键的一步是监听本地存储,而且要求每个函数在每个不同的页面中都需要有一个相同的key,这样才能实现多Tab下数据的精准共享。当前生成key的方式类似于对函数的字符串进行摘要操作,并且通过调整摘要的长度来调整key的唯一性。

    由于基于函数字符串,因此如果是实现完全一致的匿名函数则会造成冲突,这是使用中需要注意的。以下是具体的实现:

/*
	生成函数同步的key
	算法:
		1. func.toString
		2. 获取函数名(因为函数名一般不重名,因此保留整个函数名作为key前缀,但如果是匿名函数则无效)
		3. 将其中的空白符删除(IE下引号等也会导致问题)
		4. 在剩余的内容中平均取N个字符拼接成key
	算法的问题在于不同的函数内容应该不能一样,否则会出现同步异常
	通过调整字符数可以调整精度

	之所以要如此处理是为了确保每个页面对于同一个函数生成的Key是相同的,故不能使用随机数。
	这个算法的问题在于不允许函数重名。
 */
_genSyncKey: function( func ){
	//key长度
	var keyLen = 30,
		func = func.toString();
	//获取函数名
	var funcName = \'\',
		reg = /^function\\s+([^\\(]+)\\s*\\(/ig,
		matches = reg.exec( func );
	if( matches ){
		funcName = matches[1];
		funcName = funcName.replace(/[^\\w]+/ig,\'\');
	}

	func = func.replace(/(function|[^\\w]+)/ig,\'\');

	keyLen -= funcName.length;

	if( keyLen <= 0 ){
		return funcName.substring( 0, 30 );
	}

	if( func.length <= keyLen ){
		return funcName + func;
	}
	var leftCharLen = keyLen,
		funcLeftLen = func.length,
		step = Math.ceil( func.length / keyLen ),
		key = [];
	for( var i = 0; i < func.length; i += step ){
		key.push( func.substring(i, i+1) );
		leftCharLen--;
		funcLeftLen -= step;
		//检查剩余长度
		if( funcLeftLen <= leftCharLen ){
			key.push( func.substring(i) );
			break;
		}
	}
	return funcName + key.join(\'\');
}

    具体的实现中会特别保留整个函数名,但是经过压缩的代码意义不会很大,此外需要过滤特殊字符,不然IE下使用userData时会出错。

过滤当前页面触发的事件

    在sync方法的实现中,除了key得生成之外,还需要解决的问题是区分是否当前页面触发,如果是当前页面触发的onstorage则应该忽略掉,否则会造成死循环。实现方案是在特定的浏览器中加入锁进行判断,当页面执行封装后的B函数时表明是由当前页面触发的,此时会忽略onstorage事件。

参数同步

    此外,函数执行时的参数是动态的,因此是需要进行同步的,由于本地同步只限于可以进行序列化的数据,所以对同步函数的参数类型有限制,目前只支持string类型。

    以下是具体的实现:

/**
	跨页面同步指定的函数
	@param {function}	func		需要同步执行的函数(不允许重名,函数参数必须为string类型,否则参数无法同步)
	@param {Object}		context		返回的函数执行时的上下文
	@param {Boolean}	onlySync	是否只执行同步,为true时不执行原函数而只执行同步操作
	@return {function}  当执行新的函数时将会通过本地存储进行同步操作
 */
sync: function( func, context, onlySync ){
	if( !K.isFunction( func ) ) return;
	//生成存储key(对于同一个函数而言,生成的key应该相同,这样才能保证多个页面对于同一个函数监听的是同一个key)
	var key = this._genSyncKey( func );

	//数据项中前缀和数据之间的分隔符
	var split = \'~{##}~\';

	//参数之间的分隔符
	var argSplit = \'~{###}~\';

	//是否当前页面触发
	//(IE、Firefox3.6下的onstorage事件不论是否当前页面都会收到,所以需要加锁识别,确保当前页面不响应,其他浏览器则不必)
	var isLocalTrigger = false;

	//监听key变化
	this.onstorage( key, function(val){
		if( !isLocalTrigger || (!K.Browser.ie && parseInt(K.Browser.firefox) >= 4 ) ){
			var args = val.split( split )[1],
				arrArg = args.split( argSplit );
			func.apply( context, arrArg);
		}
		isLocalTrigger = false;
	});

	var ins = this;
	//返回的函数执行时,传入参数必须为string类型,否则参数无法同步
	return function( ){
		//执行原方法
		if( !onlySync ){
			func.apply( context, arguments );
		}
		isLocalTrigger = true;
		//同步(加时间戳和随机数是为了让数据项发生变化,否则其他页面无法监听到
		ins.setItem( key,
			(new Date())*1
			+ \'\'
			+ Math.random()
			+ split
			+ ([].slice.call(arguments).join(argSplit))
		);
	};
}

接口的使用

    参考示例页面:http://www.varnow.org/pages/html5/storage/sync/action_sync.html

function changeColor( id, color ){
	$( id ).style.backgroundColor = color;
}
changeColor = Storage.sync( changeColor );

$(\'test\').onclick =  function(){
	var colors = [\'red\',\'black\',\'green\',\'blue\',\'yellow\'];
	var color = colors[ Math.floor( Math.random() * 5 ) ];
	changeColor( \'test\',color );
};

function close1(){
	this.style.display = \'none\';
}

//绑定this
close1 = Storage.sync( close1, $(\'test\') );

$(\'close1\').onclick = function(){
	close1();
};

    下一篇将介绍Tab间的通信同步。

建议继续学习:

  1. HTML5 离线缓存-manifest简介    (阅读:16094)
  2. 面向移动设备的HTML5开发框架梳理    (阅读:5909)
  3. JavaScript,只有你想不到    (阅读:5087)
  4. HTML5本地存储初探(二)    (阅读:4384)
  5. Phonegap + HTML5 开发经验小结    (阅读:4102)
  6. HTML5是什么东东 我们为什么要关注    (阅读:3841)
  7. HTML5文件API之图片预览    (阅读:3659)
  8. HTML6 初探 — 你没看错,是6不是5    (阅读:3642)
  9. 让你的网站也像Gmail一样支持文件拖放上传-HTML5之File API    (阅读:3443)
  10. HTML5技术的调研以及贴吧应用总结    (阅读:3450)
QQ技术交流群:445447336,欢迎加入!
扫一扫订阅我的微信号:IT技术博客大学习
© 2009 - 2024 by blogread.cn 微博:@IT技术博客大学习

京ICP备15002552号-1