javascript 缓存系统
模仿jQuery,设计了一个缓存系统。像jQuery.data这样的东西,Prototype与mootools也有,目的都是用来辅助事件系统,用来缓存其中生成的数据,而非缓存普通函数上次计算的结果。Prototype利用了它的Hash类,mootools没细看,它内部好像用来缓存uuid。一个共识是,为页面用到的元素设置uuid非常有用,要查找元素时,可以避免重复查找,也可以用于与事件回调函数相绑定。由于uuid目前只有IE支持,它叫做uniqueID,格式为ms__id\d+,后面的数字也有名堂,叫做uniqueNumber。jQuery那个算是uniqueNumber吧,而且它的缓存系统非常复杂,支持缓存单个数据(利用data这个读写方法)与一组数据(利用queue,删除用dequeue)。没办法,因为它是白手起家,没有像Prototype那样利用一个自定数据类型分担一下职责。是时候进入正题,说一下我的缓存系统了。它利用到我的超级数组对象,实现像queue与dequeue。但我的超级数组对象能做的事更多,像filter,forEach,map,reduce,one,toObject,contains,remove等一应俱全。
dom.eventTypes = dom.array(String( "abort blur change click contextmenu \ dblclick error focus keydown keypress keyup load mousedown \ mouseenter mouseup mouseleave mousemove mouseover mouseout \ reset resize select submit unload" ).match(/\w+/g)); //******************************缓存系统*********************** dom.mixin({ uuid : 0, storage: {}, buildCache: function (item){ var key,cache = dom.storage; //如果是window if ( item.setInterval && ( item !== window && !item.frameElement )) { key = "dom-window" } else if (item.nodeType){ if (!item.uuid){ item.uuid = "dom" + dom.uuid++ dom.cache( "uuid" , "uuid-set" ,item); //保存元素的引用 } //如果当前元素没有uuid这属性,那么为它添加一个 key = item.uuid } else if (dom.isString(item)){ key = item; } else { throw "item must be element node ,window or string" } if (!cache[key]){ cache[key] = {}; } return cache[key] }, cache: function (item,name,data){ //读写缓存 var cache = dom.buildCache(item); if (data !== undefined){ if (dom.isFunction(data)){ //缓存函数,在函数设置一个uuid,生成方式取其toString()并去掉空白 var uuid = (data+ "" ).replace(/\s+/g, '' ); data.uuid = uuid; } if (!cache[name]){ //set与list允许缓存一组数据, //其中如果带有-set后缀允许其中的元素重复,list则不允许 if (/-set$/.test(name)){ //如果是第一次存储 cache[name] = array(data); cache[name].type = "set" ; } else if (/-list$/.test(name)){ // cache[name] = array(data); cache[name].type = "list" ; } else { cache[name] = data; } } else { var type = cache[name].type; if (type && type === "set" ){ cache[name].ensure(data) } else if (type && type === "list" ){ cache[name].push(data) } else { cache[name] = data; } } return item; } else { return cache[name] } }, //参数可以为1,2,3 removeCache: function (item,name,data){ if (!arguments.length) return ; var cache = dom.buildCache(item),isDOM = !!item.nodeType; if (isDOM && dom.eventTypes.contains(name)){ name = name + "-handlers-list" ; }; if (arguments.length === 3){ //移除指定的data if (cache[name] instanceof dom.array && cache[name].length > 0){ //对于由事件绑定函数构成的超级数组,我们在缓存它的时候为每个函数设置了一个uuid //现在我们比较现在传入的函数的uuid与超级数组中的某个元素的uuid是否相等 //如果有我们将得它的引用,有了它我们才能使用remove方法移除它。 if (dom.isFunction(data)){ var uuid = (data+ "" ).replace(/\s+/g, '' ), fn = cache[name].one( function (fn){ return fn.uuid == uuid; }); if (fn){ cache[name].remove(fn); } } else { cache[name].remove(data); } if (cache[name].length === 0) dom.removeCache(item,name); } else { dom.removeCache(item,name); } } else if (arguments.length === 2){ //移除条目 delete cache[name] if (!dom.isExtensible(cache)){ dom.removeCache(item); } } else { delete cache; if (isDOM){ dom.removeCache( "uuid" , "uuid-set" ,item); dom.removeAttr(item, "uuid" ); } } }, clearCache: function (){ var cache = dom.buildCache( "uuid" , "uuid-set" ); if (!cache) return ; //如果为空直接返回 cache.forEach( function (el){ dom.removeAttr(el, "uuid" ); }); dom.storage = null ; } }); |
buildCache是用于在dom.storage上开辟一个命名空间,cache用于在命名空间存储各种数据,可以为单个数据,一组数据,一组数据又分为list与set两种,区别是允许元素是否重复,重复的list相重于jQuery.queue设置的数组。对于window对象的处理,jQuery是在闭包内搞了一个windowData,我则它为在dom.storage开辟了一个名为dom-window的空间。removeCache相当于jQuery.removeData与jQuery.unquere,但功能还要强大,能根据传入参数的个数选用不同的功能。clearCache则直接删除所有缓存。
值得注意的是,在IE中为DOM元素设置私有属性会引起内存泄漏,所有在页面unload时需要手动去除它们。各大类库也是这样做了,dom.cache("uuid","uuid-set",item)就是用于unload时取出所有设置过uuid的元素,一一去掉其uuid。不过实际上,调用clearCache方法就可以了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步