localStorage過(guò)期時(shí)間設(shè)置的幾種方法
聊到 localStorage 想必熟悉前端的朋友都不會(huì)陌生, 我們可以使用它提供的 getItem, setItem, removeItem, clear 這幾個(gè) API 輕松的對(duì)存儲(chǔ)在瀏覽器本地的數(shù)據(jù)進(jìn)行**「讀,寫, 刪」操作, 但是相比于 cookie, localStorage 唯一美中不足的就是「不能設(shè)置每一個(gè)鍵的過(guò)期時(shí)間」**。
localStorage 屬性允許我們?cè)L問(wèn)一個(gè) Document 源(origin)的對(duì)象 Storage;存儲(chǔ)的數(shù)據(jù)將保存在瀏覽器會(huì)話中。 localStorage 類似 sessionStorage,但其區(qū)別在于:存儲(chǔ)在 localStorage 的數(shù)據(jù)可以長(zhǎng)期保留;而當(dāng)頁(yè)面會(huì)話結(jié)束——也就是說(shuō),當(dāng)頁(yè)面被關(guān)閉時(shí),存儲(chǔ)在 sessionStorage 的數(shù)據(jù)會(huì)被清除 。?
我們還應(yīng)注意,localStorage 中的鍵值對(duì)總是以字符串的形式存儲(chǔ)。
問(wèn)題描述
在實(shí)際的應(yīng)用場(chǎng)景中, 我們往往需要讓 localStorage 設(shè)置的某個(gè) 「key」 能在指定時(shí)間內(nèi)自動(dòng)失效, 所以基于這種場(chǎng)景, 我們?nèi)绾稳ソ鉀Q呢?
1. 初級(jí)解法
對(duì)于剛熟悉前端的朋友, 可能會(huì)立馬給出答案:
localStorage.setItem('dooring', '1.0.0') // 設(shè)置一小時(shí)的有效期 const expire = 1000 * 60 * 60; setTimeout(() => { localStorage.setItem('dooring', '') }, expire)
當(dāng)然這種方案能解決一時(shí)的問(wèn)題, 但是如果要設(shè)置任意鍵的有效期, 使用這種方案就需要編寫多個(gè)定時(shí)器, 「維護(hù)成本極高, 且不利于工程化復(fù)用」。
2. 中級(jí)解法
前端工程師在有一定的工作經(jīng)驗(yàn)之后, 往往會(huì)去考慮工程化和復(fù)用性的問(wèn)題, 并對(duì)數(shù)據(jù)結(jié)構(gòu)有了一定的了解, 所以可能會(huì)有接下來(lái)的解法:
- 用**「localStorage」**存一份{key(鍵): expire(過(guò)期時(shí)間)}的映射表
- 重寫**「localStorage API」**, 對(duì)方法進(jìn)行二次封裝
類似的代碼如下:
const store = { // 存儲(chǔ)過(guò)期時(shí)間映射 setExpireMap: (key, expire) => { const expireMap = localStorage.getItem('EXPIRE_MAP') || "{}" localStorage.setItem( 'EXPIRE_MAP', JSON.stringify({ ...JSON.parse(expireMap), key: expire })) }, setItem: (key, value, expire) => { store.setExpireMap(key, expire) localStorage.setItem(key, value) }, getItem: (key) => { // 在取值之前先判斷是否過(guò)期 const expireMap = JSON.parse( localStorage.getItem('EXPIRE_MAP') || "{}" ) if(expireMap[key] && expireMap[key] < Date.now()) { return localStorage.getItem(key) }else { localStorage.removeItem(key) return null } } // ... }
眨眼一看這個(gè)方案確實(shí)解決了復(fù)用性的問(wèn)題, 并且不同團(tuán)隊(duì)都可以使用這個(gè)方案, 但仍然有一些缺點(diǎn):
- 對(duì) store 操作時(shí)需要維護(hù)2份數(shù)據(jù), 并且占用緩存空間
- 如果 EXPIRE_MAP 誤刪除將會(huì)導(dǎo)致所有過(guò)期時(shí)間失效
- 對(duì)操作過(guò)程缺少更靈活的控制(比如操作狀態(tài), 操作回調(diào)等)
3. 高級(jí)解法
為了減少維護(hù)成本和空間占用, 并支持一定的靈活控制和容錯(cuò)能力, 我們又應(yīng)該怎么做呢?
這里筆者想到了兩種類似的方案:
- 將過(guò)期時(shí)間存到 key 中, 如 dooring|6000, 每次取值時(shí)通過(guò)分隔符“|”來(lái)將 key 和 expire 取出, 進(jìn)行判斷
- 將過(guò)期時(shí)間存到 value 中, 如 1.0.0|6000, 剩下的同1
為了更具有封裝性和可靠性, 我們還可以配置不同狀態(tài)下的回調(diào), 簡(jiǎn)單實(shí)現(xiàn)如下:
const store = { preId: 'xi-', timeSign: '|-door-|', status: { SUCCESS: 0, FAILURE: 1, OVERFLOW: 2, TIMEOUT: 3, }, storage: localStorage || window.localStorage, getKey: function (key: string) { return this.preId + key; }, set: function ( key: string, value: string | number, time?: Date & number, cb?: (status: number, key: string, value: string | number) => void, ) { let _status = this.status.SUCCESS, _key = this.getKey(key), _time; // 設(shè)置失效時(shí)間,未設(shè)置時(shí)間默認(rèn)為一個(gè)月 try { _time = time ? new Date(time).getTime() || time.getTime() : new Date().getTime() + 1000 * 60 * 60 * 24 * 31; } catch (e) { _time = new Date().getTime() + 1000 * 60 * 60 * 24 * 31; } try { this.storage.setItem(_key, _time + this.timeSign + value); } catch (e) { _status = this.status.OVERFLOW; } cb && cb.call(this, _status, _key, value); }, get: function ( key: string, cb?: (status: number, value: string | number | null) => void, ) { let status = this.status.SUCCESS, _key = this.getKey(key), value = null, timeSignLen = this.timeSign.length, that = this, index, time, result; try { value = that.storage.getItem(_key); } catch (e) { result = { status: that.status.FAILURE, value: null, }; cb && cb.call(this, result.status, result.value); return result; } if (value) { index = value.indexOf(that.timeSign); time = +value.slice(0, index); if (time > new Date().getTime() || time == 0) { value = value.slice(index + timeSignLen); } else { (value = null), (status = that.status.TIMEOUT); that.remove(_key); } } else { status = that.status.FAILURE; } result = { status: status, value: value, }; cb && cb.call(this, result.status, result.value); return result; }, // ... }; export default store;
這樣, 我們就實(shí)現(xiàn)了每個(gè) key 都有獨(dú)立的過(guò)期時(shí)間, 并且對(duì)不同的操作結(jié)果可以輕松的進(jìn)行狀態(tài)管控啦~
4. 骨灰級(jí)解法
當(dāng)然, 骨灰級(jí)解法是直接使用 xijs 這個(gè) javascript 工具庫(kù), 因?yàn)槲乙呀?jīng)將上述完整實(shí)現(xiàn)方案封裝到該庫(kù)中了, 我們只需要使用如下的方案, 就能輕松使用具有過(guò)期時(shí)間的強(qiáng)大的 「localStorage」 方法啦 :
// 先安裝 yarn add xijs import { store } from 'xijs'; // 設(shè)置帶有過(guò)期時(shí)間的key store.set('name', 'dooring', Date.now() + 1000); console.log(store.get('name')); setTimeout(() => { console.log(store.get('name')); }, 1000); // 設(shè)置成功后的回調(diào) store.set('dooring', 'xuxiaoxi', Date.now() + 1000, (status, key, value) => { console.log('success'); });
同時(shí) xijs 還在持續(xù)擴(kuò)充更有用的工具函數(shù), 讓業(yè)務(wù)開(kāi)發(fā)更高效. 目前已集成了如下工具函數(shù):
- 「store」 基于 localStorage 上層封裝的支持過(guò)期時(shí)間設(shè)置的緩存庫(kù), 支持操作回調(diào)
- 「uuid」 生成唯一id, 支持設(shè)置長(zhǎng)度
- 「randomStr」 生成指定個(gè)數(shù)的隨機(jī)字符串
- 「formatDate」 開(kāi)箱即用的時(shí)間格式化工具
- 「debounce」 防抖函數(shù)
- 「throttle」 節(jié)流函數(shù)
- 「url2obj」 將url字符串轉(zhuǎn)換為對(duì)象
- 「obj2url」 將對(duì)象轉(zhuǎn)換成編碼后的url字符串
- 「isPC」 判斷設(shè)備是否為PC類型
github地址: https://github.com/MrXujiang/xijs
文檔地址:h5.dooring.cn/xijs
到此這篇關(guān)于localStorage過(guò)期時(shí)間設(shè)置的幾種方法的文章就介紹到這了,更多相關(guān)localStorage 過(guò)期時(shí)間內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
layui實(shí)現(xiàn)數(shù)據(jù)表格隱藏列的示例
今天小編就為大家分享一篇layui實(shí)現(xiàn)數(shù)據(jù)表格隱藏列的示例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-10-10js數(shù)組常見(jiàn)操作及數(shù)組與字符串相互轉(zhuǎn)化實(shí)例詳解
這篇文章主要介紹了js數(shù)組常見(jiàn)操作及數(shù)組與字符串相互轉(zhuǎn)化方法,以實(shí)例形式較為詳細(xì)的分析并總結(jié)了JavaScript數(shù)組的常見(jiàn)使用技巧與轉(zhuǎn)化方法,需要的朋友可以參考下2015-11-11在IE和VB中支持png圖片透明效果的實(shí)現(xiàn)方法(vb源碼打包)
在IE和VB中支持png圖片透明效果的實(shí)現(xiàn)方法(vb源碼打包),需要的朋友可以參考下。2011-04-04div當(dāng)滾動(dòng)到頁(yè)面頂部的時(shí)候固定在頂部實(shí)例代碼
使用Javascript實(shí)現(xiàn)了滾動(dòng)頁(yè)面時(shí),DIV到達(dá)頂部時(shí)固定在頂部。在IE下效果有點(diǎn)閃,具體代碼如下,感興趣的朋友可以參考下哈2013-05-05js字符串轉(zhuǎn)換成數(shù)字與數(shù)字轉(zhuǎn)換成字符串的實(shí)現(xiàn)方法
本篇文章主要是對(duì)js字符串轉(zhuǎn)換成數(shù)字與數(shù)字轉(zhuǎn)換成字符串的實(shí)現(xiàn)方法進(jìn)行了詳細(xì)的介紹,需要的朋友可以過(guò)來(lái)參考下,希望對(duì)大家有所幫助2014-01-01前端進(jìn)階之教你利用javascript存儲(chǔ)函數(shù)
這篇文章主要給大家介紹了關(guān)于利用javascript存儲(chǔ)函數(shù)的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用js具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2021-11-11JavaScript的eval JSON object問(wèn)題
在做AJAX應(yīng)用開(kāi)發(fā)的時(shí)候,我們通常喜歡把服務(wù)器端返回的JSON格式字符串在客戶端的回調(diào)函數(shù)中把它作為JavaScript代碼執(zhí)行并用一個(gè)變量保存起來(lái),以方便使用返回的數(shù)據(jù)。2009-11-11