-- 作者:dogog
-- 发布时间:5/6/2007 1:22:00 AM
--
1、cache简述 讨论比较多的是J2ee中的cahce,不管是集中式,分布式可能大家基本理解都差不多。但可能有个误区,不要把cache介质当成持久化介质,我觉得判断标准是,当cache服务器瘫痪时,不影响系统的应用,只是性能上受影响。 在ajax中,我认为有两种应用场景。 a、通过xmlhttp/iframe等向服务器请求内容时。因为每次http请求消耗的时间是很多的,对不常改变的数据进行cache可以大大的加快系统响应速度,可以节约服务器资源 与j2ee比较,可能与hibernate二级缓存类似,数据cache. b、由于javascript语言性能不是很好,对于复杂的,费时的运算,我们也可以把运算结果cache.不知道大家知道不知道csdn中梅花雪做的那棵树,据说它用了cahce。 我想这类cache叫应用cache。在j2ee应用中,我一般不做数据cache,只在logic层做cache.但现在通过ROR的学习,有点怀疑logic/dao层的必要性,毕竟我们做的真是“企业应用”吗?有复杂逻辑吗? 在ajax cahce解决方案里,个人喜欢在做数据cache,也是上面的第一种。如果要在浏览器上做复杂的运算,那请你回头看看,你的设计肯定有问题,或者这个逻辑不应该由浏览器来完成。 2、ajax cache的特点 这里ajax应用程序在浏览器中,cache在不同htm/jsp...页面中不能共享。(当然iframe,frame特殊处理,可能这是cache介质的好地方) ,更麻烦的是页面刷新以后,cache会丢失,好在我们的ajax应用可以设计成single page应用。 开始正题前,我想有两个假设 (1)在single page应用中。毕竟那是大家向往的一中ajax应用方式,也是cache最能发挥作用的场景。 (2)数据cache,通过xmlhttp,iframe,dwr等框架的cache. ajax的cache远没有j2ee等服务器端复杂,应用也有一定的局限,但以下问题应该考虑: a、限制条件 b、哪些数据应该cache. c、cache key怎么设定。 d、如何应用cache呢? 3、限制条件 我想对于ajax应用来说,从服务器获取数据的入口应该是一个,例如:如果你准备用dwr,那么你程序中所有与服务器的交互必须都是DWR,如果用dojo.io。那么cache将比较难实现,必须手工编程来cache,remove cache 。不知道我的表述清楚没。就象在j2ee中,如果你用了hibernate的二级缓存,如果你用JDBC或着更新了数据库中内容,那hibernate的二级缓存内容肯定不是正确的了。所以如果要用ajax cache,与服务器交互的类库最好是一种。 cache最大好处是提高系统性能,而ajax应用能够cache的数据并不是太多(后面描述),所以我们的cache框架必须精小,并且可拔插。 dojo.io/dwr/json-rpc.....这类框架的选择也很重要。看下面分析。 4、哪些数据应该cache ajax中xmlhttp是默认传输器(dojo中用语)。如果浏览器支持,那么除了文件上传,几乎所有的功能xmlhttp都能实现,另外比起iframe等,xmlhttp是最好了。 mimetype == "text/javascript" mimetype == "text/json" mimetype = "text/html" mimetype == "application/xml" mimetype: "text/plain" 不知道大家开发过程中用到哪几种”格式“,就cahce来说,我觉得text/plain最好了,简单的文本,但实际开发过程中,最常用的是xml和json,还有html代码段。 就我知识来说,xml,json,html都可以进行cache,因为从类型上看来,它们都是数据,就象j2ee中的DTO一样,没有任何状态、逻辑,只包括数据。 我想表达的意思是,如果你需要ajax cache,那么从服务器返回的数据无论格式怎么样,但不能包括任何状态、逻辑,只包括数据。 例如dwr返回的数据其实是json,但没关系,因为它只是java DTO对象对JSON的转化,没有状态。这里需要注意,你不要改变Object.prototype对象,因为返回的是javascript 对象,如果你要cache对象,那么你不要修改这个对象的值,注意javascript与java对象一样,你得到的只是它的”句柄“。 5、cache key怎么设定 先看看dojo.io里面cache key的方法 function getCacheKey(url, query, method) { return url + "|" + query + "|" + method.toLowerCase(); } 如果你用dojo.io或YUI/prototype.js这些框架,估计这三个参数就OK了,但是query可能会长点,但是这类框架必须有servlet,或必须有struts/webwork之类的web表现层,增加了代码量,面对ajax开发人员的是一堆url和?key=value&key1=value1. dwr类框架cache key设定: Logic.method = function(p0, 01,callback) { DWREngine._execute(Logic._path, 'Logic', 'method', p0,p1, callback); } 就上面这个方法来说,CahceKey function getCacheKey(Logic._path, 'Logic', 'method', p0,p1, callback) { return Logic._path+ "|" + Logic+ "|" + p0+ "|" +p1; } 现在对于不同的callback可以用cache数据了。当然如果dwr支持cache,我们需要改写DWREngine._execute方法和DWREngine._handleResponse方法。由于代码我没测试过,但大致上应该可以。 6、如何应用cache呢 cache当然只在query时才用,但如果你的应用修改数据,你必须把cache remove掉。说起来是个简单的问题,但具体应用起来比较复杂。 在j2ee里面,有时我们用 find,get开头方法当成查询add cache,insert/update/delete开头的方法remove cache.但实际写代码时,可能不全是增删改查,有很复杂的逻辑,个人还是倾向与手工的add cache和remove cache. 在dojo.io中有个参数useCache: false,可以控制是否需要add cache。但dojo.io没有提供remove cache的API。不过这些工作得我们自己实现,如果removeAll cache就比较简单了,如果要remove(key) 就比较难实现了。 7、代码例子 仿照dojo我做了个测试代码,如下只能在FF下运行哦: 要运行以下代码,你必须建立个data.txt 放到这个htm同一目录下 <body> <INPUT TYPE="button" value="use cache" onclick="io.bind({ asyn : true, url:'data.txt', method :'GET', useCache : true, callback : log, callbackObj : window });"> <INPUT TYPE="button" value="not cache" onclick="io.bind({ asyn : true, url:'data.txt', method :'GET', useCache : false, callback : log, callbackObj : window });"> <INPUT TYPE="button" value="clear cahce" onclick="io.clearCache();"> <div id="log"></div> </body> <SCRIPT LANGUAGE="JavaScript"> <!-- function log(msg){ document.getElementById('log').innerHTML+=msg+'<br>'; } var io =new function(){ var getHttp=function(){ return new XMLHttpRequest(); }; function doLoad(callbackObj,callback,data,args){ callback.apply(callbackObj,[data]); addCache(args,data); }; var _cache={}; var getCacheKey=function(args){ return args.url + args.method.toLowerCase(); } var addCache=function(args,data){ _cache[getCacheKey(args)]=data; } var getCahce=function(args){ return _cache[getCacheKey(args)]; } this.clearCache=function(){ log('cache is empty!'); _cache={}; } this.bind=function(args){ var cacheObj=getCahce(args); if(args.useCache&&cacheObj){ log('cache is exist'); doLoad(args.callbackObj,args.callback,cacheObj,args); return; } if(args.useCache) log('cache isn\'t exist'); //cache var http=getHttp(); http.open(args.method, args.url+'?iodate='+new Date(), args.asyn); if(args.asyn){ var tempInterval=window.setInterval( function(){ if(http.readyState==4){ window.clearInterval(tempInterval); doLoad(args.callbackObj,args.callback,http.responseText,args); } } ,50) ; } http.send(null); if(!args.asyn){ doLoad(args.callbackObj,args.callback,http.responseText,args); } return false; }; }; //--> </SCRIPT>
|