聊聊前端存儲庫Localforage和存儲配額
前言
瀏覽器本地存儲,是每一個前端小伙伴都相當(dāng)熟悉的知識點(diǎn)。
目前使用率最高的當(dāng)之無愧為Web Storage API?,也就是localStorage和sessionStorage?,API簡單,讀取效率高。然后是indexedDB?,但大部分時間是存在于八股文和面試題中。indexedDB?的優(yōu)勢為存儲空間大,且支持各種數(shù)據(jù)結(jié)構(gòu),性能也沒有問題。之所以不為重用,是因?yàn)閕ndexedDB?的API多、長且紛雜。另外,前端使用數(shù)據(jù)庫還需要了解一些表、游標(biāo)、事務(wù)等一些概念,對于不了解后端的同學(xué)來說上手成本也就高出localStorage?太多。所以,在5M內(nèi)的存儲領(lǐng)域,indexedDB?并非首選。另外WebSQL?已被H5標(biāo)準(zhǔn)放棄,而元老級的Cookie也不再適合現(xiàn)代的客戶端存儲任務(wù)。
那么有沒有一個既保留indexedDB?優(yōu)點(diǎn),上手又簡單的方法呢,答案就是封裝js庫,localforage就是一個比較成熟的方案。
localforage
簡介
localforage是一個 JavaScript 庫,通過簡單類似 localStorage API 的異步存儲來改進(jìn)你的 Web 應(yīng)用程序的離線體驗(yàn)。它能存儲多種類型的數(shù)據(jù),而不僅僅是字符串。
localforage?采用優(yōu)雅降級策略,若瀏覽器不支持indexedDB? 或 WebSQL?,則使用 localStorage?。所以,在優(yōu)先選用indexedDB存儲的前提下,兼容性也得以保證,在所有主流瀏覽器中都可使用:Chrome,F(xiàn)irefox,IE 和 Safari(包括 Safari Mobile)。
localforage在github上擁有21.5k個star,npm下載量每周200w左右,正常使用也不會出現(xiàn)問題。
用法
詳細(xì)的使用方法不做過多贅述,只講一下存取示例。
- setItem
- getItem
實(shí)踐
在一次的業(yè)務(wù)需求中,基于以下兩點(diǎn),果斷選擇了localforage。
- 后期會有大量數(shù)據(jù)需要本地存儲。
- 轉(zhuǎn)轉(zhuǎn)內(nèi)部有基于localforage.js二次封裝的庫,且包含設(shè)置過期時間的方法,適用于此次需求。
上線后的一段時間,該功能平穩(wěn)運(yùn)行。直到sentry(錯誤日志監(jiān)控系統(tǒng))出現(xiàn)了大量關(guān)于內(nèi)存溢出的報錯......
問題處理
艱難復(fù)現(xiàn)
起初懷疑是localforage?有兼容性問題,但是localforage?有優(yōu)雅降級機(jī)制。再加上報錯內(nèi)容為QuotaExceededError?,所以在閱讀大量資料后基本鎖定為在indexedDB的使用上出現(xiàn)了問題。另外,報錯用戶數(shù)量為個位數(shù),說明了是用戶操作或手機(jī)存在異常導(dǎo)致的問題。
在確定了問題的大體方向,排查代碼沒有思路的前提下,眼前能做的就是復(fù)現(xiàn)這個問題。
剛才提到,QuotaExceededError為內(nèi)存溢出類型報錯,直覺告訴我,需要找一個內(nèi)存空間剩余最少的測試機(jī),但當(dāng)時最少的也剩余20GB,于是下載了一天大型軟件后,終于在內(nèi)存剩余100MB左右時成功復(fù)現(xiàn)。
問題原因
不同于瀏覽器會為localStorage?預(yù)留5MB左右的儲存空間,indexedDB的配額是動態(tài)計(jì)算的,準(zhǔn)確的說是瀏覽器的儲存配額是動態(tài)計(jì)算的,雖然瀏覽器實(shí)現(xiàn)各不相同,但可用存儲量通常取決于設(shè)備上可用的存儲量。
這個可用的存儲量稱為全局限制,F(xiàn)irefox大約為可用磁盤空間的50%,Chrome的這一數(shù)據(jù)能達(dá)到80%。如果超過此范圍,則會發(fā)起稱為源回收的過程,刪除整個源的數(shù)據(jù),直到存儲量再次低于限制。刪除源數(shù)據(jù)沒有只刪一部分的說法——因?yàn)檫@樣可能會導(dǎo)致不一致的問題。
除全局限制外,還有另一個限制稱為組限制——為全局限制的20%。這里可以把每個二級域名看作一組,每組可以聚合使用最多20%的全局限制。
如果超出組限制,或者源回收過程無法釋放足夠空間,indexedDB? 或緩存 API就會拋出名為 QuotaExceededError? 的 DOMError。
如何查看有多少可用存儲空間?
Ps.這個方法使用了StorageManager API,使用前要先對其進(jìn)行功能檢測。實(shí)測過程中,Android的webview支持此方法,ios卻不支持。
如何解決
優(yōu)雅降級只是去判斷了瀏覽器是否支持某種本地存儲的方法,但無法處理硬盤不足的問題,所以如果想去避免這個問題,可以在業(yè)務(wù)代碼中使用try...catch進(jìn)行異常捕獲,手動進(jìn)行異常處理。
業(yè)務(wù)中常用的解決辦法是彈窗提示用戶去清理手機(jī)硬盤。實(shí)測中,華為手機(jī)硬盤小于100MB時,系統(tǒng)層也會彈出清理手機(jī)的彈窗提示。
總結(jié)&思考
- localforage?是個優(yōu)秀的前端存儲js庫,某種角度來講,indexedDB?的發(fā)展要感謝localforage。
- 不論localStorage?還是indexedDB?,存儲空間都受瀏覽器存儲配額的影響,而瀏覽器的存儲配額取決于本地磁盤剩余空間的大小。配額不足就會導(dǎo)致瀏覽器報QuotaExceededError。
- 開源輪子查問題沒思路時,在代碼倉庫issue中查找會是一個捷徑,作者就忽略了這點(diǎn)繞了彎路。
參考資料
1.https://web.dev/storage-for-the-web/
2.https://developer.mozilla.org/zh-CN/docs/Web/API/IndexedDB_API/Browser_storage_limits_and_eviction_criteria
3.https://www.zhangxinxu.com/wordpress/2018/06/js-localforage-localstorage-indexdb/