jQuery 数据缓存data(name, value)详解及实现


Posted in Javascript onJanuary 04, 2010

作为一名程序员,一提到“缓存”你很容易联想到“客户端(浏览器缓存)”和“服务器缓存”。客户端缓存是存在浏览者电脑硬盘上的,即浏览器临时文件夹,而服务器缓存是存在服务器内存中,当然在一些高级应用场合也有专门的缓存服务器,甚至有利用数据库进行缓存的实现。当然这些都不在本文的讨论范围,本文要讨论的是最流行的JavaScript框架jQuery的数据缓存实现原理,这是jQuery1.2.3版开始加入的新功能。
一、 jQuery数据缓存的作用
jQuery数据缓存的作用在中文API中是这样描述的:“用于在一个元素上存取数据而避免了循环引用的风险”。如何理解这句话呢,看看我下面的举例,不知道合不合适,如果你有更好的例子可以告诉我。
(1) 存在循环引用风险的例子(注意getDataByName(name)方法中的for in语句):

<a href="javascript:void(0);" onclick="showInfoByName(this.innerHTML);">Tom</a><br/> 
<a href="javascript:void(0);" onclick="showInfoByName(this.innerHTML);">Mike</a> 
<script type="text/javascript"> 
var userInfo = [ 
{ 
"name": "Tom", 
"age": 21, 
"phone": "020-12345678" 
}, 
{ 
"name": "Mike", 
"age": 23, 
"phone": "020-87654321" 
}]; 
function getDataByName(name) 
{ 
for (var i in userInfo) 
{ 
if (userInfo[i].name == name) 
{ 
return userInfo[i]; 
break; 
} 
} 
} 
function showInfoByName(name) 
{ 
var info = getDataByName(name); 
alert('name:' + info.name + '\n' + 'age:' + info.age + '\n' + 'phone:' + info.phone); 
} 
</script>

(2) 优化循环引用风险的例子(本例子其实与jQuery缓存实现原理差不多了,本例子重点在于改写了userInfo这个JSON结构,使name与对象key直接对应):
<a href="javascript:void(0);" onclick="showInfoByName(this.innerHTML);">Tom</a><br/> 
<a href="javascript:void(0);" onclick="showInfoByName(this.innerHTML);">Mike</a> 
<script type="text/javascript"> 
var userInfo = 
{ 
"Tom": 
{ 
"name": "Tom", 
"age": 21, 
"phone": "020-12345678" 
}, 
"Mike": 
{ 
"name": "Mike", 
"age": 23, 
"phone": "020-87654321" 
} 
}; 
function showInfoByName(name) 
{ 
var info = userInfo[name]; 
alert('name:' + info.name + '\n' + 'age:' + info.age + '\n' + 'phone:' + info.phone); 
} 
</script>

二、简单实现jQuery设置数据缓存方法
jQuery数据缓存的实现其实是很简单的,下面我来实现jQuery设置数据缓存方法,我让代码尽量的简单,这有助于你更容易了解data的实现原理。函数与测试代码如下:
<div id="div1">div1</div><br/> 
<div id="div2">div2</div> 
<script type="text/javascript"> 
//cache对象结构像这样{"uuid1":{"name1":value1,"name2":value2},"uuid2":{"name1":value1,"name2":value2}},每个uuid对应一个elem缓存数据,每个缓存对象是可以由多个name/value对组成的,而value是可以是任何数据类型的,比如可以像这样在elem下存一个JSON片段:$(elem).data('JSON':{"name":"Tom","age":23}) 
var cache = {}; 
//expando作为elem一个新加属性,为了防止与用户自己定义的产生冲突,这里采用可变后缀 
var expando = 'jQuery' + new Date().getTime(); 
var uuid = 0; 
function data(elem, name, data) 
{ 
//至少保证要有elem和name两个参数才能进行取缓存或设置缓存操作 
if (elem && name) 
{ 
//尝试取elem标签expando属性 
var id = elem[expando]; 
if (data) 
{ 
//设置缓存数据 
if (!id) 
id = elem[expando] = ++uuid; 
//如果cache中id键对象不存在(即这个elem没有设置过数据缓存),先创建一个空对象 
if (!cache[id]) 
cache[id] = {}; 
cache[id][name] = data; 
} 
else 
{ 
//获取缓存数据 
if (!id) 
return 'Not set cache!'; 
else 
return cache[id][name]; 
} 
} 
} 
var div = document.getElementById('div1'); 
data(div, "tagName", "div"); 
data(div, "ID", "div1"); 
alert(data(div, "tagName")); //div 
alert(data(div, "ID")); //div1 
var div2 = document.getElementById('div2'); 
alert(data(div2, "tagName")); //Not set cache! 
</script>

三、使用jQuery数据缓存注意事项
(1)因为jQuery缓存对象是全局的,在AJAX应用中,由于页面刷新很少,这个对象将一直存在,随着你对data的不断操作,很有可能因为使用不当,使得这个对象不断变大,最终影响程序性能。所以我们要及时清理这个对象,jQuery也提供了相应方法:removeData(name),name就是你当初设置data值时使用的name参数。
另外,根据我对jQuery代码的了解,发现下面几种情况不需要手动清除数据缓存:
<1> 对elem执行remove()操作,jQuery会清除对象可能存在的缓存。jQuery相关源代码参考:
remove:function(selector) 
{ 
if (!selector || jQuery.filter(selector, [this]).length) 
{ 
// Prevent memory leaks 
jQuery("*", this).add([this]).each(function() 
{ 
jQuery.event.remove(this); 
jQuery.removeData(this); 
}); 
if (this.parentNode) 
this.parentNode.removeChild(this); 
} 
}

<2> 对elem执行empty()操作,如果当前elem子元素存在数据缓存,jQuery也会清除子对象可能存在的数据缓存,因为jQuery的empty()实现其实是循环调用remove()删除子元素。jQuery相关源代码参考:
empty:function() 
{ 
// Remove element nodes and prevent memory leaks 
jQuery(this).children().remove(); 
// Remove any remaining nodes 
while (this.firstChild) 
this.removeChild(this.firstChild); 
}

2、jQuery复制节点clone()方法不会复制data缓存,准确说jQuery不会在全局缓存对象中分配一个新节点存放新复制elem缓存。jQuery在clone()中把可能存在的缓存指向属性(elem的expando属性)替换成空。如果直接把这个属性复制,就会导致原先和新复制的elem都指向一个数据缓存,中间的互操作都将会影响到两个elem的缓存变量。以下jQuery代码就是把expando属性删除(jQuery1.3.2,较早版本不是这样处理,显然新版本的这个方法性能更好)。
jQuery.clean([html.replace(/ jQuery\d+="(?:\d+|null)"/g, "").replace(/^\s*/, "")])[0];
把数据缓存一起复制有时候也是很有用的,比如在拖动操作中,我们点击源目标elem节点就会复制出一个半透明的elem副本开始拖动,并把data缓存复制到拖动层中,等到拖动结束,我们就可能取到当前拖动的elem相关信息。现在jQuery方法没有给我们提供这样的处理,怎么办法。第一个办法是改写jQuery代码,这个方法显然很傻,很不科学。正确做法是复制源目标的data,把这些data都重新设置到复制出来的elem中,这样在执行data(name, value)方法时,jQuery会在全局缓存对象中为我们开辟新空间。实现代码如下:
if (typeof($.data(currentElement)) == 'number') 
{ 
var elemData = $.cache[$.data(currentElement)]; 
for (var k in elemData) 
{ 
dragingDiv.data(k, elemData[k]); 
} 
}

在上面代码中,$.data(elem,name,data)包含三个参数,如果只有一个elem参数,这个方法返回它的缓存key(即uuid),利用这个key就可以得到整个缓存对象,然后把对象的数据都复制到新的对象。
Javascript 相关文章推荐
javascript 选择文件夹对话框(web)
Jul 07 Javascript
JS小功能(操作Table--动态添加删除表格及数据)实现代码
Nov 28 Javascript
Javascript浅谈之this
Dec 17 Javascript
jQuery+HTML5加入购物车代码分享
Oct 29 Javascript
JS验证邮件地址格式方法小结
Dec 01 Javascript
jquery购物车结算功能实现方法
Oct 29 Javascript
web.js.字符串与正则表达式操作
May 13 Javascript
基于AngularJS实现的工资计算器实例
Jun 16 Javascript
提升页面加载速度的插件InstantClick
Sep 12 Javascript
Vue2.0点击切换类名改变样式的方法
Aug 22 Javascript
详解小程序循环require之坑
Mar 08 Javascript
微信小程序非跳转式组件授权登录的方法示例
May 22 Javascript
用AJAX返回HTML片段中的JavaScript脚本
Jan 04 #Javascript
Javascript解决常见浏览器兼容问题的12种方法
Jan 04 #Javascript
javascript 模拟点击广告
Jan 02 #Javascript
javascript 多种搜索引擎集成的页面实现代码
Jan 02 #Javascript
让firefox支持IE的一些方法的javascript扩展函数代码
Jan 02 #Javascript
javascript getElementsByClassName 和js取地址栏参数
Jan 02 #Javascript
firefox插件Firebug的使用教程
Jan 02 #Javascript
You might like
关于php连接mssql:pdo odbc sql server
2011/07/20 PHP
php实现的click captcha点击验证码类实例
2014/09/23 PHP
Yii2实现增删改查后留在当前页的方法详解
2017/01/13 PHP
PHP中函数gzuncompress无法使用的解决方法
2017/03/02 PHP
PHP递归实现汉诺塔问题的方法示例
2017/11/25 PHP
for 循环性能比较 提高for循环的效率
2009/03/19 Javascript
GWT中复制到剪贴板 js+flash实现复制 兼容性比较好
2010/03/07 Javascript
你必须知道的Javascript知识点之&quot;深入理解作用域链&quot;的介绍
2013/04/23 Javascript
js中继承的几种用法总结(apply,call,prototype)
2013/12/26 Javascript
删除节点的jquery代码
2014/01/13 Javascript
JavaScript操作Cookie方法实例分析
2015/05/27 Javascript
JavaScript中利用for循环遍历数组
2017/01/15 Javascript
Bootstrap学习笔记 轮播(Carousel)插件
2017/03/21 Javascript
vue组件初学_弹射小球(实例讲解)
2017/09/06 Javascript
原生js实现简单的模态框示例
2017/09/08 Javascript
详细分析jsonp的原理和实现方式
2017/11/20 Javascript
vue实现的组件兄弟间通信功能示例
2018/12/04 Javascript
JS栈stack类的实现与使用方法示例
2019/01/31 Javascript
微信小程序3种位置API的使用方法详解
2019/08/05 Javascript
vue实现整屏滚动切换
2020/06/29 Javascript
vue中实现点击变成全屏的多种方法
2020/09/27 Javascript
Python时区设置方法与pytz查询时区教程
2013/11/27 Python
Python使用sftp实现上传和下载功能(实例代码)
2017/03/14 Python
python 动态迁移solr数据过程解析
2019/09/04 Python
Django框架 querySet功能解析
2019/09/04 Python
python计算导数并绘图的实例
2020/02/29 Python
印度低票价航空公司:GoAir
2017/10/11 全球购物
致铅球运动员加油稿
2014/02/13 职场文书
珍惜水资源建议书
2014/03/12 职场文书
教师师德演讲稿
2014/05/06 职场文书
社区领导班子四风问题原因分析及整改措施
2014/09/28 职场文书
社区班子个人对照检查材料思想汇报
2014/10/07 职场文书
2016年“5.12”护士节慰问信
2015/11/30 职场文书
pycharm安装深度学习pytorch的d2l包失败问题解决
2022/03/25 Python
Ruby GDBM操作简介及数据存储原理
2022/04/19 Ruby
windows安装 redis 6.2.6最新步骤详解
2022/04/26 Redis