在很多公司中,內(nèi)部都會(huì)封裝一些適用于公司內(nèi)部業(yè)務(wù)的方法庫(kù)來提高整個(gè)團(tuán)隊(duì)的開發(fā)效率,比如:
而在 Vue3 項(xiàng)目中,這種方法庫(kù)表現(xiàn)為:hooks庫(kù),市面上有很多優(yōu)秀的庫(kù),比如:vueuse。
最近我在面試中,喜歡問一道有關(guān)于 hooks 的開放問題:二次封裝一個(gè) loaclStorage 的 hooks 時(shí),需要考慮哪些問題呢?
其實(shí)這是一道很簡(jiǎn)單的題,只不過想考考面試者在做業(yè)務(wù)的時(shí)候,會(huì)不會(huì)考慮更多的邊界情況~接下來說說我對(duì)這個(gè)問題的小小的理解(可能也不是很全面)。
比如我現(xiàn)在一個(gè)域名下有兩個(gè)子項(xiàng)目:
且這兩個(gè)項(xiàng)目都需要存儲(chǔ) userInfo,那要怎么防止這兩組數(shù)據(jù)互相污染呢?所以需要注意命名,在存儲(chǔ)的時(shí)候加上對(duì)應(yīng)的項(xiàng)目名前綴,或者其他標(biāo)識(shí)符,保證這組數(shù)據(jù)是唯一的
const PROJECT_NAME = 'test-project'localStorage.setItem( `${PROJECT_NAME}_userInfo`, JSON.stringify({ name: 'lsx' }))
請(qǐng)看一個(gè)例子,假如我們存儲(chǔ)一段信息,類型是 string
// 存數(shù)據(jù)const set = () => { const info = get() if (!info) { localStorage.setItem( `${PROJECT_NAME}_info`, 'info_string' ) }}// 取數(shù)據(jù)const get = () => { const info = localStorage.getItem( `${PROJECT_NAME}_info` ) return info}
然后項(xiàng)目上線了一段時(shí)間,但是這個(gè)時(shí)候,突然決定要換成 object 類型了,這時(shí)候?qū)?yīng)的存取方法也變了
// 存數(shù)據(jù)const set = () => { const info = get() if (!info) { localStorage.setItem( `${PROJECT_NAME}_info`, JSON.stringify({ name: 'lsx' }) ) }}// 取數(shù)據(jù)const get = () => { const info = localStorage.getItem( `${PROJECT_NAME}_info` ) return JSON.parse(info)}
但是這樣其實(shí)是有隱患的,因?yàn)轫?xiàng)目已經(jīng)上線了一段時(shí)間,有些用戶已經(jīng)存過這個(gè)數(shù)據(jù)了,且存的是 string 類型,但是新版本上線之后,取數(shù)據(jù)卻用了 object 的方式去取數(shù)據(jù),這就導(dǎo)致了JSON.parse(字符串)會(huì)報(bào)錯(cuò),影響正常的業(yè)務(wù)邏輯~
所以最好是加一個(gè)版本號(hào),或者做一下錯(cuò)誤兼容,這樣就能避免了~
const PROJECT_NAME = 'test-project'// 每次升級(jí)時(shí)改變版本號(hào),規(guī)則自己定const VERSION = 1// 存數(shù)據(jù)localStorage.setItem( `${PROJECT_NAME}_userInfo_${VERSION}`, JSON.stringify({ name: 'lsx' }))// 取數(shù)據(jù)localStorage.getItem( `${PROJECT_NAME}_userInfo_${VERSION}`)
時(shí)效性,那就是給存進(jìn)去的數(shù)據(jù)加一個(gè)時(shí)效,過了某個(gè)時(shí)間,這個(gè)數(shù)據(jù)就時(shí)效了,方法就是每次存數(shù)據(jù)進(jìn)去的時(shí)候,加一個(gè)時(shí)間戳:
// 原來localStorage.setItem( `${PROJECT_NAME}_userInfo`, JSON.stringify({ name: 'lsx' }))const TIME_OUT = 3 * 60 * 60 * 1000// 加時(shí)間戳localStorage.setItem( `${PROJECT_NAME}_userInfo`, JSON.stringify({ data: { name: 'lsx' }, // 記錄當(dāng)前時(shí)間 time: new Date().getTime() }))// 取數(shù)據(jù)時(shí)判斷時(shí)間戳const get = () => { let info = localStorage.getItem( `${PROJECT_NAME}_userInfo_${VERSION}` ) info = JSON.parse(info) const now = new Date().getTime() if (now - info.time >= TIME_OUT) { localStorage.removeItem( `${PROJECT_NAME}_userInfo_${VERSION}` ) return null } return info}
有一些數(shù)據(jù)我們不得不存在 localStorage 中,但是又不想被用戶看到,這時(shí)候就需要進(jìn)行加密了(加密規(guī)則自己定):
// 加密函數(shù)const encrypt = (v) => {}// 解密函數(shù)const decrypt = (v) => {}// 存數(shù)據(jù)localStorage.setItem( `${PROJECT_NAME}_userInfo_${VERSION}`, // 加密 encrypt(JSON.stringify({ name: 'lsx' })))// 取數(shù)據(jù) 解密decrypt(localStorage.getItem( `${PROJECT_NAME}_userInfo_${VERSION}`))
SSR 就是服務(wù)端渲染,是在服務(wù)端運(yùn)行代碼,拼接成一個(gè)頁面,發(fā)送到瀏覽器去展示出來,所以在服務(wù)端是使用不了 localStorage 的,因?yàn)椴皇菫g覽器環(huán)境,所以你像封裝一個(gè)比較通用的 localStorage,得兼顧 SSR 的情況:
// 在 SSR 中使用對(duì)象替代 localStorageconst SSRStorage = { map: {}, setItem(v) { this.map[key] = v }, getItem(key) { return this.map[key] }}let storage = null// 判斷環(huán)境if (!window) { storage = SSRStorage} else { storage = window.localStorage}
本文鏈接:http://www.tebozhan.com/showinfo-26-76567-0.html我面試最喜歡問的開放題:如何嚴(yán)謹(jǐn)二次封裝 localStorage?
聲明:本網(wǎng)頁內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com
上一篇: 面試官:工作中處理過什么復(fù)雜的前端需求,如何解決的?
下一篇: Redis鎖被別人釋放怎么辦