場景
瀏覽器端需要存儲一個用戶的標識和cookie
一樣需要過期時間,但是用的是localStorage
存儲。而localStorage
一經存儲除非手動刪除是不會過期的。那就需要自己實現過期機制。網上找了幾種簡單的方法。
方案一:ES5擴展Storage
思路很簡單,存儲的值加一個時間戳,下次取值時驗證時間戳。
注意: localStorage
只能存儲字符,存入時將對象轉為json
字符串,讀取時也要解析
Storage.prototype.setExpire = (key, value, expire) => {
let obj = {
data: value,
time: Date.now(),
expire: expire
};
//localStorage 設置的值不能為對象,轉為json字符串
localStorage.setItem(key, JSON.stringify(obj));
}
Storage.prototype.getExpire = key => {
let val = localStorage.getItem(key);
if (!val) {
return val;
}
val = JSON.parse(val);
if (Date.now() - val.time > val.expire) {
localStorage.removeItem(key);
return null;
}
return val.data;
}
測試一下:
localStorage.setExpire('userId','zhangsan',5000);
window.setInterval(()=>{
console.log(localStorage.getExpire("userId"));
},1000)
前5秒還是有值的,之后即為null
方案二:ES6擴展Storage
大體思路和方案一是一樣的只不過是用了ES6的最新語法實現。
class Storage {
constructor(props) {
this.props = props || {}
this.source = this.props.source || window.localStorage
this.initRun();
}
initRun(){
/*
* set 存儲方法
* @ param {String} key 鍵
* @ param {String} value 值,存儲的值可能是數組/對象,不能直接存儲,需要轉換 JSON.stringify
* @ param {String} expired 過期時間,以分鍾為單位
*/
const reg = new RegExp("__expires__");
let data = this.source;
let list = Object.keys(data);
if(list.length > 0){
list.map((key,v)=>{
if( !reg.test(key )){
let now = Date.now();
let expires = data[`${key}__expires__`]||Date.now+1;
if (now >= expires ) {
this.remove(key);
};
};
return key;
});
};
}
set(key, value, expired) {
/*
* set 存儲方法
* @ param {String} key 鍵
* @ param {String} value 值,
* @ param {String} expired 過期時間,以毫秒為單位,非必須
*/
let source = this.source;
source[key] = JSON.stringify(value);
if (expired){
source[`${key}__expires__`] = Date.now() + expired
};
return value;
}
get(key) {
/*
* get 獲取方法
* @ param {String} key 鍵
* @ param {String} expired 存儲時為非必須字段,所以有可能取不到,默認為 Date.now+1
*/
const source = this.source,
expired = source[`${key}__expires__`]||Date.now+1;
const now = Date.now();
if ( now >= expired ) {
this.remove(key);
return;
}
const value = source[key] ? JSON.parse(source[key]) : source[key];
return value;
}
remove(key) {
const data = this.source,
value = data[key];
delete data[key];
delete data[`${key}__expires__`];
return value;
}
}
其中set()
,get()
,remove()
方法可以理解用來存、取、刪, initRun()
做什么用呢?過期的值只有取時才能知道是不是過期,不取一直存着。initRun()
和constructor
只是在初始化時實現清理,也不是一定即時。另外寫一個定時器去清理貌似也不值當,所以覺得做到這樣已經夠用了。
使用如下代碼進行測試一下,效果和方案一相同
var ls=new Storage();
ls.set('userId','zhangsan',5000);
window.setInterval(()=>{
console.log(ls.get("userId"));
},1000)