運用惰性刪除和定時刪除實現可過期的localStorage快取
- 2020 年 6 月 1 日
- 筆記
- localStorage, 快取
localStorage簡介
使用localStorage可以在瀏覽器中存儲鍵值對的數據。經常被和localStorage一併提及的是sessionStorage,它們都可以在當瀏覽器中存儲鍵值對的數據。但是它們之間的區別是:存儲在localStorage的數據可以長期保留;而當頁面會話結束(也就是當頁面被關閉)時,存儲在sessionStorage的數據會被清除。
另外需要注意的是,localStorage中的鍵值對總是以字元串的形式存儲,並且只能訪問當前域名下的數據,不能跨域名訪問。
歡迎關注微信公眾號:萬貓學社,每周一分享Java技術乾貨。
localStorage方法
可以通過setItem
方法增加了一個鍵值對數據,比如:
localStorage.setItem('name', 'OneMore');
如果該鍵已經存在,那麼該鍵對應的值將被覆蓋。還可以使用getItem
方法讀取對應鍵的值數據,比如:
var name = localStorage.getItem('name');
可以使用removeItem
方法移除對應的鍵,比如:
localStorage.removeItem('name');
也可以使用clear
方法移除當前域名下所有的鍵值對數據,比如:
localStorage.clear();
歡迎關注微信公眾號:萬貓學社,每周一分享Java技術乾貨。
可過期的localStorage快取
正如上面所提到的,localStorage只能用於長久保存整個網站的數據,保存的數據沒有過期時間,直到手動去刪除。所以要實現可過期的localStorage快取的中重點就是:如何清理過期的快取?
惰性刪除
惰性刪除是指,某個鍵值過期後,該鍵值不會被馬上刪除,而是等到下次被使用的時候,才會被檢查到過期,此時才能得到刪除。我們先來簡單實現一下:
var lsc = (function (self) {
var prefix = 'one_more_lsc_'
/**
* 增加一個鍵值對數據
* @param key 鍵
* @param val 值
* @param expires 過期時間,單位為秒
*/
self.set = function (key, val, expires) {
key = prefix + key;
val = JSON.stringify({'val': val, 'expires': new Date().getTime() + expires * 1000});
localStorage.setItem(key, val);
};
/**
* 讀取對應鍵的值數據
* @param key 鍵
* @returns {null|*} 對應鍵的值
*/
self.get = function (key) {
key = prefix + key;
var val = localStorage.getItem(key);
if (!val) {
return null;
}
val = JSON.parse(val);
if (val.expires < new Date().getTime()) {
localStorage.removeItem(key);
return null;
}
return val.val;
};
return self;
}(lsc || {}));
上述程式碼通過惰性刪除已經實現了可過期的localStorage快取,但是也有比較明顯的缺點:如果一個key一直沒有被用到,即使它已經過期了也永遠存放在localStorage。為了彌補這樣缺點,我們引入另一種清理過期快取的策略。
歡迎關注微信公眾號:萬貓學社,每周一分享Java技術乾貨。
定時刪除
定時刪除是指,每隔一段時間執行一次刪除操作,並通過限制刪除操作執行的次數和頻率,來減少刪除操作對CPU的長期佔用。另一方面定時刪除也有效的減少了因惰性刪除帶來的對localStorage空間的浪費。
每隔一秒執行一次定時刪除,操作如下:
- 隨機測試20個設置了過期時間的key。
- 刪除所有發現的已過期的key。
- 若刪除的key超過5個則重複步驟1,直至重複500次。
具體實現如下:
var lsc = (function (self) {
var prefix = 'one_more_lsc_'
var list = [];
//初始化list
self.init = function () {
var keys = Object.keys(localStorage);
var reg = new RegExp('^' + prefix);
var temp = [];
//遍歷所有localStorage中的所有key
for (var i = 0; i < keys.length; i++) {
//找出可過期快取的key
if (reg.test(keys[i])) {
temp.push(keys[i]);
}
}
list = temp;
};
self.init();
self.check = function () {
if (!list || list.length == 0) {
return;
}
var checkCount = 0;
while (checkCount < 500) {
var expireCount = 0;
//隨機測試20個設置了過期時間的key
for (var i = 0; i < 20; i++) {
if (list.length == 0) {
break;
}
var index = Math.floor(Math.random() * list.length);
var key = list[index];
var val = localStorage.getItem(list[index]);
//從list中刪除被惰性刪除的key
if (!val) {
list.splice(index, 1);
expireCount++;
continue;
}
val = JSON.parse(val);
//刪除所有發現的已過期的key
if (val.expires < new Date().getTime()) {
list.splice(index, 1);
localStorage.removeItem(key);
expireCount++;
}
}
//若刪除的key不超過5個則跳出循環
if (expireCount <= 5 || list.length == 0) {
break;
}
checkCount++;
}
}
//每隔一秒執行一次定時刪除
window.setInterval(self.check, 1000);
return self;
}(lsc || {}));
完整源碼及使用示例
完整源碼及使用示例已上傳到我的GitHub(//github.com/heihaozi/LocalStorageCache)上,感謝各位小夥伴的Star和Fork。
總結
一種策略可能會有自己的缺點,為了規避相應的缺點,我們可以合理運用多種策略,揚長避短就得到接近完美的解決方案。
微信公眾號:萬貓學社
微信掃描二維碼
獲得更多Java技術乾貨
