摘要:于是一個擁有版本控制和過期控制的本地內(nèi)容存儲功能模塊就算初步完成了。最后基于這個事情的考慮,于是順便寫了個本地存儲控制的庫,基本都在上面了
前言
關(guān)于localStorage sessionStorage之類的api怎么用已經(jīng)無需我再贅述了,但是具體怎么落實到一個稍微復(fù)雜一些的業(yè)務(wù)中還是需要做一些前期的準(zhǔn)備
遇見的一些問題1.localStorage 與 sessionStorage具體適用于什么樣的業(yè)務(wù)場景?
2.如何維護本地儲存?
3.如何進行版本控制?
4.碰到禁止本地緩存的情況下怎么解決這個問題?
根據(jù)本身特性localStorage做長期存儲, sessionStorage做臨時存儲大家都是清楚的也無需贅述,至于IndexedDB之類的暫時不做討論。
很多初級的前后端分離的項目習(xí)慣性誤區(qū)是把用戶token存到localStorage。
這時候碰到一個問題:
如果需要在不同域名下做登陸信息共享該怎么辦?
常見做法是SSO,同一個域名下的小型項目用cookies的domain直接來做簡單的跨域共享也是一個辦法,而這個時候localStorage和sessionStorage就出現(xiàn)業(yè)務(wù)盲點了。
不僅過不去,即使通過各種鬼畜的操作過去了后面擦屁股也麻煩的要死:
登陸了以后用戶信息怎么傳給別的域名?
退登的話怎么刪除所有頁面的登陸狀態(tài)?
當(dāng)然如果需要實現(xiàn)還是比較依賴后端的用戶登陸狀態(tài)判定,而這個時候某些分離得過分干凈的業(yè)務(wù)可能出現(xiàn)一些詭異的狀態(tài)判定,比如a.xxx.com站退登了b.xxx.com站還登著,你要真要前端來做這事代碼量也是相當(dāng)可觀的,甚至各個頁面緩存的token數(shù)據(jù)可能還都不一樣,顯然不夠合理也不適合這樣用,請把后端的事情還給后端,除非前端也寫一些node中間層。
而且某些瀏覽器的無痕功能禁用了localStorage和sessionStorage導(dǎo)致登陸狀態(tài)異常,所以localStorage存用戶token的事情就把它忘記吧,不然后面就等著哭吧。
存些不常變的東西?
比如圖片,把圖片轉(zhuǎn)成base64再存起來?
那么問題來了,一般我們會存什么圖片?
比如一些背景圖?
那么為了這件事情我們首次載入的時候先要把圖片下載過來,然后費盡心思存起來還要避免和別的同事重名,萬一哪天要換個圖片還要想辦法把之前的內(nèi)容清理掉不然直接讀localStorage里的內(nèi)容,即使做好了本地存儲的版本控制還要專門寫一大堆代碼增刪改查,這明顯是嫌自己工作量不夠大,本來只要用cdn直接解決的東西被搞得這么費勁,何必呢?
所以存文件的事情基本也可以忽略了。
還有一些神奇的做法是存js代碼,敢這樣做的人不是蠢就是壞了。
然后,一般localStorage常用于緩存一些內(nèi)容很多很固定的數(shù)據(jù)比如全國各地省市縣、區(qū)號之類的基本不會變但又會在各種ui組件里用到的簡單數(shù)據(jù),但是直接JSON.parse然后還去遍歷一個很大的數(shù)據(jù)做查詢篩選只會讓你的機器感到絕望發(fā)紅發(fā)燙瀕臨崩潰,而這個時候我還不如直接用cdn載入一個專門用于存放這類靜態(tài)數(shù)據(jù)的js文件來得快捷方便性能還好還能隨時改。
難道localStorage真的這么廢?
其實也不是啦,首先要確定一點,不去存過大的JSON數(shù)據(jù),那就存?zhèn)€小的:
用戶搜索歷史的緩存。
文本編輯器內(nèi)輸入的內(nèi)容。
然后是sessionStorage,其實我最喜歡用這個了,關(guān)掉就清除毫無后顧之憂,那一般我會用于什么業(yè)務(wù)場景呢:
怎么存?存網(wǎng)頁的歷史記錄,操作過histroyAPI的朋友一定知道為了避免安全性問題histroy只會給你當(dāng)前頁面前面打開過幾個頁面的數(shù)量。所以完全可以在這里做個histroy的詳細記錄,甚至結(jié)合spa項目的router插件來滿足各類奇怪的需求,比如跳了好幾次頁面填了一堆表格后點擊支付然后支付完成后即使點擊瀏覽器頂部的后退按鈕也能直接一腳跨回首頁。
或者存那堆臨時表格的內(nèi)容(2B業(yè)務(wù)經(jīng)常碰到那種填一大堆又臭又長的申請表還要經(jīng)過各種審批的功能)
存用戶個人信息,比如用戶昵稱之類的,不用每次刷新都去服務(wù)器拖一遍(當(dāng)然這種事情其實還是有一定風(fēng)險的,萬一用戶在別的地方改昵稱了,你還得想辦法同步,具體解決辦法后面說)
很多人第一反應(yīng)可能是直接使用 localStorage.setItem之類的api
一旦你真的只這樣做了...我可能無法保證你不被同事揍
每個業(yè)務(wù)線本身應(yīng)該有個狀態(tài)的管理區(qū)域,而這些業(yè)務(wù)線的本地數(shù)據(jù)存儲業(yè)務(wù)應(yīng)該匯總?cè)氲揭粋€公共的入口做類型判定以及進行增刪改查。
一般比如Vue的應(yīng)用,我們會把數(shù)據(jù)存到Vuex的state內(nèi),每個業(yè)務(wù)線分支都會有多帶帶的模塊引入并進行獨立維護。
你必須確定一個習(xí)慣一致,名字唯一的命名協(xié)議。
自娛自樂的項目也就罷了,萬一是個超過四個人的前端小隊每年可能都有不同的人會離職不同的人會入職不同的業(yè)務(wù)要迭代不同的功能要修改,增刪改查的事情如果沒有一個確定的標(biāo)準(zhǔn)后果不堪設(shè)想。
一般常見命名方式會在前面帶入業(yè)務(wù)模塊名稱
比如 USER_INFORMATION_NICKNAME 之類的,當(dāng)然有的信息可能不方便透露只寫個索引名稱也是有的,主要還是看公司里決定這個規(guī)則的人怎么考慮。
還是以Vuex做為例子(以下內(nèi)容僅供參考,請勿直接用于業(yè)務(wù)代碼中)
在State中聲明對象用于獲取本地存儲內(nèi)容的元數(shù)據(jù)
state:{ NICKNAME: window.localStorage.getItem("USER_INFORMATION_NICKNAME") }
創(chuàng)建一個Getter用于內(nèi)容讀取
getters: { USER_INFORMATION_NICKNAME: state => { try { return JSON.parse(state.NICKNAME) } catch (e) { localStorage.removeItem("USER_INFORMATION_NICKNAME") return null } } }
寫入Mutation用于增刪改
mutations: { DELETE_USER_INFORMATION_NICKNAME (state) { window.localStorage.removeItem("USER_INFORMATION_NICKNAME") state.USER_INFORMATION_NICKNAME = value }, UPDATE_USER_INFORMATION_NICKNAME (state, value) { window.localStorage.setItem("USER_INFORMATION_NICKNAME", value) state.USER_INFORMATION_NICKNAME = null } }
寫入Action用于信息同步
actions: { GET_USER_INFORMATION_NICKNAME:context => { $http .get("xxx") .then(res=> { context.commit("UPDATE_INFORMATION_NICKNAME", res) }) .catch(e => xxx...) } }
這樣一個最最最基本的讀取策略已經(jīng)完成了。
但問題又來了
畢竟是永久緩存,版本控制非常重要,不然就是給自己挖坑
首先要明確刪除數(shù)據(jù)的具體場景
可能是只存一小段時間后就失效的內(nèi)容
可能是下個大版本會被迭代掉的內(nèi)容
可能會發(fā)起部分用戶要升級部分用戶維持現(xiàn)狀甚至因為新版本業(yè)務(wù)不夠完善可能需要回滾的灰度更新。
一般情況下我們需要在getter內(nèi)先確定一個數(shù)據(jù)讀取的依賴項,讀取的內(nèi)容可能是跟著依賴項數(shù)據(jù)走也可能不跟著依賴項數(shù)據(jù)走,這個看具體業(yè)務(wù)需求,如果不跟著依賴項走或者本身就是被依賴的項目的話就需要確定幾件事情
版本
過期時間
可能該內(nèi)容依賴于父級項 0.0.1版本的內(nèi)容,超過或者低于這個版本都可能出現(xiàn)問題需要及時刪除并重新獲取
可能當(dāng)前載入的頁面中的配置項的版本與自身版本不一致所以需要移除并更新數(shù)據(jù)
于是導(dǎo)致的結(jié)果是我們需要再去聲明一個不保存在本地的配置JSON
{ "USER_INFORMATION": { "NICKNAME": "1.1.1", "AGE": "1.1.2" ... } }
如果要進行灰度更新的話,這個配置就需要寫入到接口里面了。
還有個情況就是設(shè)置過期時間,超出這個限定的時間就清空數(shù)據(jù)。
于是我們就需要在UPDATE方法內(nèi)多寫入些東西
UPDATE_USER_INFORMATION_NICKNAME (state, value) { const new_value = { expires: Date.now() + 24 * 1000 * 30 * 3600, version: state.config.USER_INFORMATION.NICKNAME, value: value } window.localStorage.setItem("USER_INFORMATION_NICKNAME", JSON.stringify(new_value)) state.USER_INFORMATION_NICKNAME = new_value }
再調(diào)整下讀取的邏輯,
其他的代碼也跟著做一遍調(diào)整,依照自己能力水平能封裝的封裝,能復(fù)用的復(fù)用。
于是一個擁有版本控制和過期控制的本地內(nèi)容存儲功能模塊就算初步完成了。
做完這一切雖然感覺好像是像那么回事了
后面的問題也只是封裝業(yè)務(wù)中的判斷邏輯罷了...
所以,有一個健壯的前端數(shù)據(jù)流才是核心,其他的只不過是幫助頁面達到更好的體驗的輔助功能罷了,東西再好也不能濫用。
基于這個事情的考慮,于是順便寫了個本地存儲控制的庫,api基本都在上面了
GITHUB:steerable-storrage
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/93464.html
摘要:于是一個擁有版本控制和過期控制的本地內(nèi)容存儲功能模塊就算初步完成了。最后基于這個事情的考慮,于是順便寫了個本地存儲控制的庫,基本都在上面了 前言 關(guān)于localStorage sessionStorage之類的api怎么用已經(jīng)無需我再贅述了,但是具體怎么落實到一個稍微復(fù)雜一些的業(yè)務(wù)中還是需要做一些前期的準(zhǔn)備 遇見的一些問題 1.localStorage 與 sessionStorage...
摘要:寫在前面月到這天,前端提升營,騰訊大佬們分享個人經(jīng)驗,使出各種前端方面的大招。并且減輕服務(wù)器的負擔(dān),的原則是按需取數(shù)據(jù),可以最大程度的減少冗余請求和響應(yīng)對服務(wù)器造成的負擔(dān)??刂票韱慰丶慕脿顟B(tài)。 寫在前面 5月24到30這7天,IMWeb前端提升營,騰訊大佬們分享個人經(jīng)驗,使出各種前端方面的大招。從中學(xué)習(xí)了很多前端方面的知識,也get到了前端學(xué)習(xí)的方法論,還有一些算法知識等等。 現(xiàn)將...
摘要:說明我寫這篇文章的目的其實是想科普一下基礎(chǔ)的數(shù)據(jù)傳輸和交互流程,其實也就是寫協(xié)議相關(guān)的一些東西。同樣,相對于后端程序來說也無外乎就是一大堆有一定意義的字符串,而對于腳本來說,就是表示一個數(shù)據(jù)對象。 說明 我寫這篇文章的目的其實是想科普一下基礎(chǔ)的數(shù)據(jù)傳輸和交互流程,其實也就是寫http協(xié)議相關(guān)的一些東西。而寫這篇文章也主要是源于最近和長久以來很多人問的問題都是有關(guān)于這塊的(可能問題并不是...
閱讀 718·2021-09-24 09:48
閱讀 2516·2021-08-26 14:14
閱讀 542·2019-08-30 13:08
閱讀 1475·2019-08-29 15:22
閱讀 3112·2019-08-29 11:06
閱讀 1029·2019-08-26 18:26
閱讀 1131·2019-08-26 13:53
閱讀 2605·2019-08-26 12:21