昨天看了司徒正美的博客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。