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 相关文章推荐
基于jQuery中对数组进行操作的方法
Apr 16 Javascript
JavaScript实现显示函数调用堆栈的方法
Apr 21 Javascript
微信小程序通过api接口将json数据展现到小程序示例
Jan 20 Javascript
JavaScript中递归实现的方法及其区别
Sep 12 Javascript
JS实现简单获取最近7天和最近3天日期的方法
Apr 18 Javascript
angularJS开发注意事项
May 26 Javascript
详解如何在webpack中做预渲染降低首屏空白时间
Aug 22 Javascript
vue实例中data使用return包裹的方法
Aug 27 Javascript
微信小程序学习笔记之表单提交与PHP后台数据交互处理图文详解
Mar 28 Javascript
js实现图片区域可点击大小随意改变(适用移动端)代码实例
Sep 11 Javascript
antd vue table跨行合并单元格,并且自定义内容实例
Oct 28 Javascript
微信小程序实现通讯录列表展开收起
Nov 18 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程序中的常见漏洞进行攻击(下)
2006/10/09 PHP
php设计模式 DAO(数据访问对象模式)
2011/06/26 PHP
php中将图片gif,jpg或mysql longblob或blob字段值转换成16进制字符串
2011/08/23 PHP
phpMyAdmin出现无法载入 mcrypt 扩展,请检查PHP配置的解决方法
2012/03/26 PHP
php实现概率性随机抽奖代码
2016/01/02 PHP
thinkphp3.2中实现phpexcel导出带生成图片示例
2017/02/14 PHP
PHP单例模式模拟Java Bean实现方法示例
2018/12/07 PHP
Laravel5.1 框架数据库操作DB运行原生SQL的方法分析
2020/01/07 PHP
不懂JavaScript应该怎样学
2008/04/16 Javascript
JavaScript 上万关键字瞬间匹配实现代码
2013/07/07 Javascript
扩展JS Date对象时间格式化功能的小例子
2013/12/02 Javascript
iframe实用操作锦集
2014/04/22 Javascript
js 判断所选时间(或者当前时间)是否在某一时间段的实现代码
2015/09/05 Javascript
js操作数组函数实例小结
2015/12/10 Javascript
Ajax的概述与实现过程
2016/11/18 Javascript
JavaScript基于DOM操作实现简单的数学运算功能示例
2017/01/16 Javascript
基于Bootstrap模态对话框只加载一次 remote 数据的解决方法
2017/07/09 Javascript
Angular4实现图片上传预览路径不安全的问题解决
2017/12/25 Javascript
layui type2 通过url给iframe子页面传值的例子
2019/09/06 Javascript
Vue如何实现变量表达式选择器
2021/02/18 Vue.js
Python兔子毒药问题实例分析
2015/03/05 Python
浅谈Python2获取中文文件名的编码问题
2018/01/09 Python
matplotlib命令与格式之tick坐标轴日期格式(设置日期主副刻度)
2019/08/06 Python
python使用 request 发送表单数据操作示例
2019/09/25 Python
python argparser的具体使用
2019/11/10 Python
Python计算IV值的示例讲解
2020/02/28 Python
基于python生成英文版词云图代码实例
2020/05/16 Python
Python调用Redis的示例代码
2020/11/24 Python
CSS3不透明度实例讲解
2016/04/26 HTML / CSS
SOA面试题:如何在SOA中实现松耦合
2013/07/21 面试题
会计学专业自荐信
2014/06/25 职场文书
党委书记个人对照检查材料
2014/09/15 职场文书
2015年个人审计工作总结
2015/04/07 职场文书
幼儿园食品安全责任书
2015/05/08 职场文书
TV动画《政宗君的复仇》第二季制作决定PV公布
2022/04/02 日漫
numpy array找出符合条件的数并赋值的示例代码
2022/06/01 Python