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 相关文章推荐
js判断变量是否空值的代码
Oct 26 Javascript
基于jQuery的前端数据通用验证库
Aug 08 Javascript
浏览器环境下JavaScript脚本加载与执行探析之动态脚本与Ajax脚本注入
Jan 19 Javascript
关于Vue.js 2.0的Vuex 2.0 你需要更新的知识库
Nov 30 Javascript
Jquery中attr与prop的区别详解
May 27 jQuery
JS实现经典的中国地区三级联动下拉菜单功能实例【测试可用】
Jun 06 Javascript
基于复选框demo(分享)
Sep 27 Javascript
基于iScroll实现内容滚动效果
Mar 21 Javascript
基于Vue实现图片在指定区域内移动的思路详解
Nov 11 Javascript
Node爬取大批量文件的方法示例
Jun 28 Javascript
优雅的使用javascript递归画一棵结构树示例代码
Sep 22 Javascript
Vue路由对象属性 .meta $route.matched详解
Nov 04 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+MYSQL实现用户的增删改查
2015/03/24 PHP
总结PHP内存释放以及垃圾回收
2018/03/29 PHP
javascript 面向对象编程 function也是类
2009/09/17 Javascript
JavaScript var声明变量背后的原理示例解析
2013/10/12 Javascript
在JS中解析HTML字符串示例代码
2014/04/16 Javascript
jQuery实现的原图对比窗帘效果
2014/06/15 Javascript
jQuery中的编程范式详解
2014/12/15 Javascript
轻松创建nodejs服务器(2):nodejs服务器的构成分析
2014/12/18 NodeJs
jQuery中DOM操作实例分析
2015/01/23 Javascript
省市区三级联动下拉框菜单javascript版
2015/08/11 Javascript
nodejs判断文件、文件夹是否存在及删除的方法
2017/11/10 NodeJs
微信小程序自定义弹窗实现详解(可通用)
2019/07/04 Javascript
前后端常见的几种鉴权方式(小结)
2019/08/04 Javascript
layui实现显示数据表格、搜索和修改功能示例
2020/06/03 Javascript
JS forEach跳出循环2种实现方法
2020/06/24 Javascript
vue中keep-alive、activated的探讨和使用详解
2020/07/26 Javascript
[02:04]2014DOTA2国际邀请赛 DK一个时代的落幕
2014/07/21 DOTA
python读取json文件并将数据插入到mongodb的方法
2015/03/23 Python
Python 异常处理的实例详解
2017/09/11 Python
简单了解什么是神经网络
2017/12/23 Python
python二分法查找算法实现方法【递归与非递归】
2019/12/06 Python
利于python脚本编写可视化nmap和masscan的方法
2020/12/29 Python
Hunter Boots美国官方网站:赫特威灵顿雨靴
2018/06/16 全球购物
伦敦最受欢迎的蛋糕店:Konditor & Cook
2019/11/01 全球购物
什么是规则表达式
2012/05/03 面试题
涉外文秘个人求职的自我评价
2013/10/07 职场文书
恶搞卫生巾广告词
2014/03/18 职场文书
小学生春游活动方案
2014/08/20 职场文书
公司离职证明范本(汇总)
2014/09/10 职场文书
党员四风自我剖析材料思想汇报
2014/09/13 职场文书
综合测评自我评价
2015/03/06 职场文书
晚会开场白和结束语
2015/05/29 职场文书
教师法制教育培训学习心得体会
2016/01/14 职场文书
创业计划书之服装
2019/10/07 职场文书
JavaScript 语句之常用 for 循环详解
2021/03/29 Javascript
Redis全局ID生成器的实现
2022/06/05 Redis