jQuery的缓存机制浅析


Posted in Javascript onJune 07, 2014

前不久在研究jQuery的动画队列的时候,发现jQuery的缓存系统也很强大,尽管以前也稍微接触过,但一直都没有深入研究过。jQuery的缓存系统在外部应用的时候都比较简单,比如要将某个URL数据存到缓存中只要这么写:

var val = "stylechen.com";
$("div").data( "url" ); // 返回undefined
$("div").data( "url", val ); // 返回"stylechen.com"
$("div").data( "url" ); // 返回"stylechen.com"

不光可以存储字符串,上面的val也可以是任意数据,对象、数组、函数等都可以存到里面。仅仅实现这种功能还是挺简单的,声明一个全局对象用来存储数据,然后使用data方法来存储或返回数据:

var cacheData = {}; // 用来存储数据的全局对象
var data = function( key, val ){
 if( val !== undefined ){
  cacheData[key] = val;
 }
 return cacheData[key];
}; 

jQuery缓存系统的真正魅力在于其内部应用中,动画、事件等都有用到这个缓存系统。之前在写easyAnim的时候,我将动画的队列都存储到各DOM元素的自定义属性中,这样虽然可以方便的访问队列数据,但也同时带来了隐患。如果给DOM元素添加自定义的属性和过多的数据可能会引起内存泄漏,所以要尽量避免这么干。

如果是使用jQuery的缓存系统来存放DOM元素的数据,会先给该DOM元素添加一个随机生成的属性,这个属性用来存放访问缓存数据的索引值,就好比DOM元素都有一把开启缓存保险箱的钥匙,只要有了钥匙就可以随时开启缓存保险箱。将本来存放到DOM元素中的数据都转到了缓存中,而DOM元素本身只要存储一个简单的属性就可以了,这样就可以将由DOM元素引起的内存泄漏的风险规避到最小。下面是我模拟jQuery自己写的一个简单的缓存系统:

var cacheData = {}, // 用来存储数据的全局对象
 uuid = 0,
 // 声明随机数
 expando = "cacheData" ( new Date() "" ).slice( -8 ); var data = function( key, val, data ){
 if( typeof key === "string" ){
  if( val !== undefined ){
   cacheData[key] = val;
  }

  return cacheData[key];
 }
 else if( typeof key === "object" ){
  var index,
   thisCache;
  if( !key[expando] ){
   // 添加一个DOM元素的属性 
   // 随机数是属性名 索引值是属性值
   index = key[expando] = uuid;
   thisCache = cacheData[index] = {};
  }
  else{
   index = key[expando];
   thisCache = cacheData[index];
  }
  
  if( !thisCache[expando] ){
   thisCache[expando] = {};
  }
  if( <a href="http://3water.com">gambling</a> data !== undefined ){
   // 将数据存到缓存对象中
   thisCache[expando][val] = data;
  }
  // 返回DOM元素存储的数据
  return thisCache[expando][val];
 }
};
var removeData = function( key, val ){
 if( typeof key === "string" ){
  delete cacheData[key];
 }
 else if( typeof key === "object" ){
  if( !key[expando] ){
   return;
  }
  // 检测对象是否为空
  var isEmptyObject = function( obj ) {
    var name;
    for ( name in obj ) {
     return false;
    }
    return true;
   },
   removeAttr = function(){
    try{
     // IE8及标准浏览器可以直接使用delete来删除属性
     delete key[expando];
    }
    catch (e) {
     // IE6/IE7使用removeAttribute方法来删除属性
     key.removeAttribute(expando);
    }
   },
   index = key[expando];
  if( val ){
   // 只删除指定的数据
   delete cacheData[index][expando][val];
   // 如果是空对象 索性全部删除
   if( isEmptyObject( cacheData[index][expando] ) ){
    delete cacheData[index];
    removeAttr();
   }
  }
  else{
   // 删除DOM元素存到缓存中的所有数据
   delete cacheData[index];
   removeAttr();
  }
 }
};

上面的代码值得注意的是IE6/IE7中用delete来删除自定义的属性会报错,只能使用removeAttribute来删除,标准的浏览器都可以使用delete来删除。下面是调用的结果:

var box = document.getElementById( "box" ),
 list = document.getElementById( "list" );data( box, "myName", "chen" );
alert( data( box, "myName" ) ); // chen

data( box, "myBlog", "stylechen.com" );
alert( data( box, "myBlog" ) ); // stylechen.com
removeData( box, "myBlog" );
alert( data( box, "myBlog" ) ); // undefined
alert( data( box, "myName" ) ); // chen
alert( box[expando] ); // 1
removeData( box );
alert( box[expando] ); // undefined

当然,jQuery的缓存系统比我的这个要复杂些,不过核心原理还是一样的。easyAnim将会在后续的版本中引入这个缓存系统。

Javascript 相关文章推荐
[原创]图片分页查看
Aug 28 Javascript
javascript jQuery插件练习
Dec 24 Javascript
multiSteps 基于Jquery的多步骤滑动切换插件
Jul 22 Javascript
js判读浏览器是否支持html5的canvas的代码
Nov 18 Javascript
特殊情况下如何获取span里面的值
May 20 Javascript
js父页面与子页面不同时显示的方法
Oct 16 Javascript
JS获取和修改元素样式的实例代码
Aug 06 Javascript
React Native模块之Permissions权限申请的实例相机
Sep 28 Javascript
PHP实现基于Redis的MessageQueue队列封装操作示例
Feb 02 Javascript
redux.js详解及基本使用
May 24 Javascript
javascript异步处理与Jquery deferred对象用法总结
Jun 04 jQuery
原生js添加一个或多个类名的方法分析
Jul 30 Javascript
Firefox中使用outerHTML的2种解决方法
Jun 07 #Javascript
jQuery 顶部导航跟随滚动条滚动固定浮动在顶部
Jun 06 #Javascript
判断iframe里的页面是否加载完成
Jun 06 #Javascript
javascript获取隐藏元素(display:none)的高度和宽度的方法
Jun 06 #Javascript
js中的hasOwnProperty和isPrototypeOf方法使用实例
Jun 06 #Javascript
jquery数组过滤筛选方法grep()简介
Jun 06 #Javascript
js实现的标题栏新消息闪烁提示效果
Jun 06 #Javascript
You might like
在同一窗体中使用PHP来处理多个提交任务
2008/05/08 PHP
PHP+jQuery+Ajax实现分页效果 jPaginate插件的应用
2015/10/09 PHP
项目中应用Redis+Php的场景
2016/05/22 PHP
PHP使用DOM对XML解析处理操作示例
2019/07/04 PHP
Javascript document.referrer判断访客来源网址
2020/05/15 Javascript
jquery如何实现在加载完iframe的内容后再进行操作
2013/09/10 Javascript
Javascript基础教程之变量
2015/01/18 Javascript
JavaScript监听和禁用浏览器回车事件实例
2015/01/31 Javascript
JavaScript定时显示广告代码分享
2015/03/02 Javascript
在Node.js中使用HTTP上传文件的方法
2015/06/23 Javascript
Kindeditor在线文本编辑器如何过滤HTML
2016/04/14 Javascript
Angular Module声明和获取重载实例代码
2016/09/14 Javascript
mvc 、bootstrap 结合分布式图简单实现分页
2016/10/10 Javascript
JS实现隔行换色的表格排序
2017/03/27 Javascript
JavaScrpt中如何使用 cookie 设置查看与删除功能
2017/07/09 Javascript
vue通过滚动行为实现从列表到详情,返回列表原位置的方法
2018/08/31 Javascript
axios使用拦截器统一处理所有的http请求的方法
2018/11/02 Javascript
JavaScript查看代码运行效率console.time()与console.timeEnd()用法
2019/01/18 Javascript
Vue中跨域及打包部署到nginx跨域设置方法
2019/08/26 Javascript
Python是编译运行的验证方法
2015/01/30 Python
自己编程中遇到的Python错误和解决方法汇总整理
2015/06/03 Python
使用 Python 实现微信公众号粉丝迁移流程
2018/01/03 Python
Python Numpy 实现交换两行和两列的方法
2019/06/26 Python
浅析python 通⽤爬⾍和聚焦爬⾍
2020/09/28 Python
一文彻底解决HTML5页面中长按保存图片功能
2019/06/10 HTML / CSS
英国外籍人士的在线超市:British Corner Shop
2019/06/03 全球购物
网管求职信
2014/03/03 职场文书
物流管理专业推荐信
2014/09/06 职场文书
公司离职证明范本(5篇)
2014/09/17 职场文书
2015年音乐教师个人工作总结
2015/05/20 职场文书
员工手册董事长致辞
2015/07/29 职场文书
python实现ROA算子边缘检测算法
2021/04/05 Python
MySQL获取所有分类的前N条记录
2021/05/07 MySQL
React 高阶组件HOC用法归纳
2021/06/13 Javascript
Flask使用SQLAlchemy实现持久化数据
2021/07/16 Python
日本官方排名前10的动漫,名侦探柯南上榜,第一是一部创造历史的动漫
2022/03/18 日漫