前端页面利用localStorage设置缓存方案
前端页面利用localStorage设置缓存方案
localStorage
的存储空间大致在5M左右,各大浏览器略有差别。我再chrome 54中测试能放下 5233962 字节,该值并不精确,通过每次往localStorage中插入一个大字符串,到达上线报错之后再取总长度得到。LocalStorageClient
类提供两个方法来存储缓存数据- save(key, data, flag)
saveAssignCount(preKey, variableKey, count, data, flag)
- save()函数直接存储数据项;
- saveAssignCount()函数存储数据项前会先判断同一个
preKey
的缓存条数是否大于count
,如果大于则先删除最早存储的数据项; - 比如活动详情只想缓存10条,就可以使用
saveAssignCount
函数存储,preKey
为cache_activity_detail_
,variableKey
为活动id - 缓存数据时会将用户信息和当前时间戳一同存储,以用于判断数据是否过期和数据是否有效(在同一个mall下面)
提供
load(key, overtime)
函数来读取缓存数据,超时时间为分钟。如果找到符合要求的数据则返回,否则返回null
。数据超时或者不在同一个mall下面则删除当前key缓存。提供全局参数
cacheEnable
来控制是否启用缓存,此参数可用从服务端获取或者直接前端指定。不启动缓存时save
、saveAssignCount
函数直接返回false
,load
函数直接返回null
缓存数据项尽量为不变或者变化很少的数据。列表页不适用缓存或者只缓存不带查询条件的第一页且缓存时间为分钟级,避免用户不通强刷用。
缓存的使用比较简单,请求服务器之前先获取缓存,如果缓存数据不为空则不请求服务器,如果为空则请求服务器成功之后将结果缓存起来。下面是云雀项目知识库文章详情中缓存的用法
App.Controllers.ArticleDetail = function() {
this.getArticleDetail = function(articleId) {
var CACHE_ARTICLE_DETAIL_KEY = "cache_article_detail_"; // cache key
var result = localStorageClient.load(CACHE_ARTICLE_DETAIL_KEY + articleId, 24 * 60); // load cache, 缓存24小时
if (result != null) {
// 获取到缓存直接渲染
articleDetailController.renderDetail(result);
return;
}
if (!isOnline) {
// 离线,从参数中获取
result = {data: takeOutParamObject()};
articleDetailController.renderDetail(result);
} else {
var detailModel = new BaseModel({businessUrl : "wiki/article_detail.do"});
//调用fetch时请求的url为model里面封装好的url
detailModel.fetch({
reset: true,
dataType: "jsonp", //固定值
jsonp: "callback", //值可变,名称随意,但一般设为callback就可以了
data: "sessionId=" + sessionId + "&id=" + articleId,
success: function (model) {
var result = model.toJSON();
if (result.ret == -2) {
gotoAppLogin(result.txt);
} else if (result.ret != 0) {
log4JS.info("loginVetifyGetPhone failed. " + result.txt);
dialogWarn();
} else {
// 渲染前写缓存
localStorageClient.saveAssignCount(CACHE_ARTICLE_DETAIL_KEY, articleId, 4, result, false);
articleDetailController.renderDetail(result);
}
},
error: function (model) {
log4JS.info("loginVetifyGetPhone failed. http status not 200");
dialogWarn();
}
});
}
};
this.renderDetail = function(result) {
var view = new BaseView({ el: $("#articleDetailPage .main"), model: result, renderModel: "html", tpl: "articleDetailTPL" });
view.trigger("change");
setTimeout(function(){
$("#articleDetailPage .article-content > table").wrap("<div class="table-wrapper"/>");
}, 0);
};
}
- 附录,
LocalStorageClient
类源码
class LocalStorageClient {
//添加键值对
put(key, value) {
localStorage.setItem(key, value);
}
//添加json对象
putJSON(key, json) {
localStorage.setItem(key, JSON.stringify(json));
}
//根据key查找JSON对象
getJSON(key) {
if (localStorage.getItem(key) == "undefined")
return null;
return JSON.parse(localStorage.getItem(key));
}
//根据key查找value
get(key) {
if(localStorage.getItem(key) == "undefined")
return null;
return localStorage.getItem(key)
}
//移除key对应的元素
remove(key) {
localStorage.removeItem(key);
}
//清空localStorage
clear () {
localStorage.clear();
}
//根据索引获得item,结果为一个json对象 {key,value}
indexOf(index) {
var item = {};
if (localStorage.length <= index){
return null;
}
var key = localStorage.key(i);
var value = localStorage.getItem(key);
item.key = key;
item.value = value;
return item;
}
/**
* localStorage缓存数据方法
* key: localStorage存储的key值,不以“cache_”开头的key,一律自动加上"cache_"前缀
* data: 存储的数据
* flag: 是否和用户相关 true or false
*/
save(key, data, flag) {
if (!key || !data || !cacheEnable) {
return false;
}
key = this._buildCacheKey(key);
var d = {
data: data,
timestamp: Date.now()
};
if (flag) {
var user = this._getUser();
d.user = user;
}
try {
this.putJSON(key, d);
} catch (e) {
// 异常,超出容量限制,清空缓存
this.clearCache();
return false;
}
return true;
}
/**
* localStorage缓存数据方法
* preKey: 存储的key值前缀,不以“cache_”开头的key,一律自动加上"cache_"前缀
* variableKey: key值可变部分,如id
* count: 相同前缀key下最多可以存储多少条
* data: 存储的数据
* flag: 是否和用户相关 true or false
*/
saveAssignCount(preKey, variableKey, count, data, flag) {
if (!preKey || !data || !cacheEnable) {
return false;
}
preKey = this._buildCacheKey(preKey);
var d = {
data: data,
timestamp: Date.now()
};
if (flag) {
var user = this._getUser();
d.user = user;
}
if (this.getJSON(preKey + variableKey) == null) {
// 不是同键值,需要检测是否需要删除老数据
var cacheData = new Array();
for (var i = 0; i < localStorage.length; i++ ) {
var storageKey = localStorage.key(i);
if (storageKey.indexOf(preKey) == 0) {
// 取相同前缀key的缓存对象的key和时间,以便数量超过时删除
cacheData.push({key:storageKey, time: this.getJSON(storageKey).timestamp});
}
}
if (cacheData.length > count) {
// 按时间从小到达排列
cacheData.sort(function(a, b) {
return (b.time - a.time);
})
for (var j = cacheData.length - 1; j >= count; j--) {
this.remove(cacheData[j].key);
}
}
}
try {
this.putJSON(preKey + variableKey, d);
} catch (e) {
// 异常,超出容量限制,清空缓存
this.clearCache();
return false;
}
return true;
}
/**
* 从localStorage读取缓存数据方法
* key: localStorage存储的key值
* overtime: 超时时间(分钟),默认60分钟
*/
load(key, overtime) {
if (!key || !cacheEnable) {
return null;
}
key = this._buildCacheKey(key);
var d = this.getJSON(key);
if (d == null) {
return null;
}
if (isNaN(overtime) || overtime < 0) {
overtime = 60;
}
var user = this._getUser();
if (d.timestamp + overtime * 60 * 1000 > Date.now()) {
// 时间在有效期内
if (!d.user || d.user === user) {
// 存储的数据和用户无关或者同一用户
return d.data;
} else {
// 不同用户,清除缓存
this.remove(key);
return null;
}
} else {
// 超过有效期,清除缓存
this.remove(key);
return null;
}
}
// 读写缓存信息时的用户(这里取商户的cookie)
_getUser() {
if (document.cookie.length > 0) {
var c_name = "YZ_KB_SUPPLIER_ID";
c_start = document.cookie.indexOf(c_name + "=")
if (c_start != -1) {
c_start = c_start + c_name.length + 1
c_end = document.cookie.indexOf(";", c_start)
if (c_end == -1) c_end = document.cookie.length
return unescape(document.cookie.substring(c_start, c_end));
}
}
return "unknown";
}
// 不以“cache_”开头的key,一律自动加上"cache_"前缀
_buildCacheKey(key) {
if (key.indexOf("cache_") !== 0) {
return "cache_" + key;
}
return key;
}
/**
* 删除缓存数据"cache_"开头的
*/
clearCache {
for (var i = 0; i < localStorage.length; i++ ) {
var storageKey = localStorage.key(i);
if (storageKey.indexOf("cache_") === 0) {
localStorage.removeItem(storageKey);
}
}
}
}
window.localStorageClient = new LocalStorageClient();
声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。
- 上一篇: iOS 判断字符串是否含有某种字符
- 下一篇: Java输出数组的内容