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 相关文章推荐
setInterval()和setTimeout()的用法和区别示例介绍
Nov 17 Javascript
js左右弹性滚动对联广告代码分享
Feb 19 Javascript
CSS3,HTML5和jQuery搜索框集锦
Dec 02 Javascript
避免jQuery名字冲突 noConflict()方法
Jul 30 Javascript
jQuery实现智能判断固定导航条或侧边栏的方法
Sep 04 Javascript
微信小程序  modal弹框组件详解
Oct 27 Javascript
JS中使用 after 伪类清除浮动实例
Mar 01 Javascript
微信小程序 flex实现导航实例详解
Apr 26 Javascript
详解Angular 4.x NgTemplateOutlet
May 24 Javascript
Vue代码分割懒加载的实现方法
Nov 23 Javascript
基于JS实现html中placeholder属性提示文字效果示例
Apr 19 Javascript
浅谈Vuex注入Vue生命周期的过程
May 20 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中的phpinfo()函数
2013/06/06 PHP
windows下配置apache+php+mysql时出现问题的处理方法
2014/06/20 PHP
php中的ini配置原理详解
2014/10/14 PHP
WordPress中is_singular()函数简介
2015/02/05 PHP
php发送邮件的问题详解
2015/06/22 PHP
js判读浏览器是否支持html5的canvas的代码
2013/11/18 Javascript
jquery实现的图片点击滚动效果
2014/04/29 Javascript
javascript框架设计之浏览器的嗅探和特征侦测
2015/06/23 Javascript
如何使用jQuery技术开发ios风格的页面导航菜单
2015/07/29 Javascript
VueJS全面解析
2016/11/10 Javascript
AngularJs 利用百度地图API 定位当前位置 获取地址信息
2017/01/18 Javascript
关于axios返回空对象的问题解决
2017/04/04 Javascript
微信小程序开发图片拖拽实例详解
2017/05/05 Javascript
浅谈pc端rem字体设置的问题
2017/08/03 Javascript
JavaScript 通过Ajax 动态加载CheckBox复选框
2017/08/31 Javascript
使用webpack-dev-server处理跨域请求的方法
2018/04/18 Javascript
深入浅出 Vue 系列 -- 数据劫持实现原理
2019/04/23 Javascript
JavaScript中AOP的实现与应用
2019/05/06 Javascript
vue 项目引入echarts 添加点击事件操作
2020/09/09 Javascript
使用Vant完成通知栏Notify的提示操作
2020/11/11 Javascript
Python入门篇之字典
2014/10/17 Python
线程和进程的区别及Python代码实例
2015/02/04 Python
python+influxdb+shell编写区域网络状况表
2018/07/27 Python
python TF-IDF算法实现文本关键词提取
2019/05/29 Python
Django 自定义分页器的实现代码
2019/11/24 Python
Django数据模型中on_delete使用详解
2020/11/30 Python
python opencv肤色检测的实现示例
2020/12/21 Python
html5绘制时钟动画
2014/12/15 HTML / CSS
Html5 audio标签样式的修改
2016/01/28 HTML / CSS
小学优秀辅导员事迹材料
2014/05/11 职场文书
个人担保书格式范文
2014/05/12 职场文书
工会2014法制宣传日活动总结
2014/11/01 职场文书
师范生教育见习总结
2015/06/23 职场文书
导游词之澳门妈祖庙
2019/12/19 职场文书
Prometheus 监控MySQL使用grafana展示
2021/08/30 MySQL
nginx中proxy_pass各种用法详解
2021/11/07 Servers