javascript数据缓存策略之本地存储
昨天看了司徒正美的博客http://www.cnblogs.com/rubylouvre/archive/2012/09/14/2684061.html讲到一个很完美的文件加载方案,思考很久,收益颇深。他考虑的很全面,但是美中不足的是并没有考虑ie6、7的情况,ie6、7下单个文件最大值能存64K,很多大文件是无法加载的,尤其是新版的jquery。
如果把这个思路再扩展一下,放到数据缓存里面来,将是一个很完美的解决方案。
我们先完成一个本地存储的DB类。
db = function() { var store = window.localStorage, doc = document.documentElement; if (!store) { doc.style.behavior = 'url(#default#userData)'; } return { /** * 保存数据 */ set : function(key, val, context) { if (store) { return store.setItem(key, val, context); } else { doc.setAttribute(key, value); return doc.save(context || 'default'); } }, /** * 读取数据 */ get : function(key, context) { if (store) { return store.getItem(key, context); } else { doc.load(context || 'default'); return doc.getAttribute(key) || ''; } }, /** * 删除数据 * @param {Object} * @param {Object} */ rm : function(key, context) { if (store) { return store.removeItem(key, context); } else { context = context || 'default'; doc.load(context); doc.removeAttribute(key); return doc.save(context); } }, /** * 清空数据 */ clear : function() { if (store) { return store.clear(); } else { doc.expires = -1; } } }; }();
然后我们再写一个简单的ajax函数。
if ( typeof window.XMLHttpRequest === "undefined") { window.XMLHttpRequest = function() { return new window.ActiveXObject(navigator.userAgent.indexOf("MSIE 5") >= 0 ? "Microsoft.XMLHTTP" : "Msxml2.XMLHTTP"); }; } ajax = function(uri, options) { var httpRequest, httpSuccess, timeout, isTimeout = false, isComplete = false, noop = function() { }; options = { method : options.method || "GET", data : options.data || null, arguments : options.arguments || null, onSuccess : options.onSuccess || noop, onError : options.onError || noop, onComplete : options.onComplete || noop, onTimeout : options.onTimeout || noop, isAsync : options.isAsync || true, timeout : options.timeout ? options.timeout : 30000, contentType : options.contentType ? options.contentType : "utf-8", type : options.type || "xml" }; uri = uri || ""; timeout = options.timeout; httpRequest = new window.XMLHttpRequest(); httpRequest.open(options.method, uri, options.isAsync); //设置编码集 httpRequest.setRequestHeader("Content-Type", options.contentType); /** * @ignore */ httpSuccess = function(r) { try { return (!r.status && location.protocol == "file:") || (r.status >= 200 && r.status < 300) || (r.status == 304) || (navigator.userAgent.indexOf("Safari") > -1 && typeof r.status == "undefined"); } catch(e) { } return false; } /** * @ignore */ httpRequest.onreadystatechange = function() { if (httpRequest.readyState == 4) { if (!isTimeout) { var o = {}; o.responseText = httpRequest.responseText; o.responseXML = httpRequest.responseXML; o.data = options.data; o.status = httpRequest.status; o.uri = uri; o.arguments = options.arguments; if (httpSuccess(httpRequest)) { if (options.type === "script") { eval.call(window, data); } options.onSuccess(o); } else { options.onError(o); } options.onComplete(o); } isComplete = true; //删除对象,防止内存溢出 httpRequest = null; } }; httpRequest.send(options.data); window.setTimeout(function() { var o; if (!isComplete) { isTimeout = true; o = {}; o.uri = uri; o.arguments = options.arguments; options.onTimeout(o); options.onComplete(o); } }, timeout); return httpRequest; };
好了,最后说一下解决方案,源码如下:
var cacheData = {}; cache = function(url, func, cacheTime) { //先读内存 if(cacheData[url]){ func.call(this, cacheData[url]); return; }else{ var me = this, chData = db.get(url), chTime = db.get(url + "__time"), now = new Date().getTime(), cacheTime = cacheTime || 60, ct = now - 60000 * cacheTime, //默认缓存时间为1个小时 success = function(data) { var res = data.responseText; cacheData[url] = res; db.set(url, res); db.set(url + "__time", now); func.call(me, res); }; //存在数据的情况 if (chData && chTime) { //未过期的情况 if (ct < chTime) { func.call(this, chData); } else {//过期的情况 ajax(url, {'onSuccess' : success}); } } else { ajax(url, {'onSuccess' : success}); } } }
over。