小程序 LRU 存儲設計

寫在前面

爲了解決小程序生成分享到朋友圈圖片的問題,咱們開啓了畫家計劃--- 一個小程序圖片生成庫。該計劃已開源,可移步:github.com/Kujiale-Mob… 。 你們知道 Canvas 的繪製有不少很蛋疼的坑,其中一個是它的 drawImage 方法,該方法在 IDE 中能夠直接設置爲網絡圖片的 url 進行繪製,但在真機上沒法這樣作。有這個坑後,咱們就須要先把圖片經過 download 下載到本地後,才能進行繪製。因此你的小程序中,若是有頻繁繪製一些圖片的需求,而又須要用到網絡圖片素材,這就致使每次繪製都要從新下載素材圖片,產生很大的繪製性能問題。html

小程序自己是未提供文件 LRU 之類的緩存機制的。爲了讓咱們的畫家計劃圖片生成的更快,咱們本身開發了的小程序文件進行 LRU 存儲的相關代碼。這樣咱們就無需重複下載可能會頻繁使用到的繪圖素材,大大增長了繪圖速度。git

介紹下小程序的緩存系統

小程序的緩存分爲數據緩存,和文件緩存兩部分。而文件緩存又分爲臨時文件緩存,和本地文件存儲。其中本地文件存儲的大小限制爲 10M。github

數據緩存

咱們可使用小程序提供的一套異步和同步的方法來增刪查結構化數據。同一個微信用戶,同一個小程序的存儲上限爲 10MB。若是空間不足時會在小程序級別進行 LRU,也就是不常用的小程序的數據緩存區域會被所有清空。小程序

詳細見微信官方文檔:api

developers.weixin.qq.com/miniprogram…緩存

注:數據緩存區在體驗版、開發版、和線上版都共用一套,並不會隔離。bash

文件臨時緩存

咱們在調用 wx.downloadFile 或者 wx.chooseImage 等獲取文件或圖片的方式成功後,咱們會獲得這個文件或圖片的臨時存儲路徑。文檔上寫的是臨時路徑的生命週期是在本次小程序啓動期間內微信

不過沒有對存儲大小的限制進行說明,因此理論上無論多大文件均可以進行臨時緩存,固然若是太大確定會形成某些神奇的錯誤吧。網絡

本地存儲

咱們在得到臨時文件後,能夠經過調用接口 wx.saveFile 把臨時文件存儲到本地空間中,本地空間存儲限制爲 10M。若是存儲滿了後,後面的文件就沒法存儲成功了,會報超出最大存儲上限的錯誤。數據結構

而咱們如今須要作的就是在這個本地存儲空間上,開闢一個空間,做爲咱們下載文件的存儲空間,因空間有限,因此咱們須要對這塊空間進行 LRU 管理。

有關本地存儲相關的接口可看如下文檔:

developers.weixin.qq.com/miniprogram…

注:把臨時文件經過調用 saveFile 成功後,這個臨時文件路徑就無效了。切記切記。

文件 LRU 存儲實現

小程序端的本地存儲有 10M 限制,但卻無 LRU,如今咱們須要結合上面提到的小程序三種存儲方式來實現一套小程序文件下載的 LRU 機制。

數據結構設計

{
'key': {
        'path': // 文件的存儲路徑
        'time': // 時間戳,用來記錄文件的最後訪問時間,當存儲不夠時,會選擇最遠未被訪問的文件進行刪除
        'size': // 文件大小
       }
....
'totalSize': // 全部存儲文件的當前總大小
}
複製代碼

其中咱們用下載的 url 做爲 key。 以上數據結構會存在在數據緩存區(後續咱們會把這個區域稱爲 storage 區),而且在下載器構建之時會從 storage 中讀取到內存中。之後的文件操做,也會實時同步到 storage 中記錄的文件信息。

你能夠理解爲,storage 中存儲了文件的基本信息,而 path 就至關於指向這個實際文件的指針。

整體流程設計

容錯

由於 storage 的存儲,和文件操做都是異步的,因此有可能存在二者不一致的狀況。此處的不一致狀況分兩種

第一種,storage 的某文件信息被刪除了,但文件自己卻由於出現神奇錯誤而未被刪除。另外文件添加成功了,但 storage 中卻未添加成功也屬於此狀況。

第二種,storage 中文件信息刪除失敗,可是文件卻被刪除了。

以上兩種性質不一樣,因此也須要區別對待。針對第一種會致使文件的存儲空間和 storage 中記錄的文件信息不一致,也即出現了遊離的文件(未被 storage 跟蹤)。

而第二種,至關於存在了空指針,此種狀況是絕對須要避免的,由於這會致使你在拿出一個不存在的文件使用。會直接致使嚴重bug。

針對以上兩種特殊狀況,作了如下容錯的處理。首先咱們要保證文件的刪除操做必定要在 storage 成功以後進行。這樣保證了第二種不會出錯。

而針對第一種遊離文件的狀況。咱們這邊會在 saveFile 的時機進行兜底處理。若是存在了遊離文件,最終會致使咱們空間總大小計算不一致,這可能最終會致使,咱們外部邏輯認爲能夠存儲,但實際存儲空間已經滿了,這樣就會致使 saveFile 報錯,在 saveFile 出錯後,無論啥緣由,咱們都把涉及到本策略存儲相關的內容所有清空掉,從新來過。由於咱們一直有 tempFilePath 兜底,因此即便這種狀況出現,也不會影響用戶正常使用。只是會影響一點用戶體驗(畢竟一會兒沒有之前的緩存了)。

注:之因此不像保證第二種狀況的方式來保證第一種狀況,是由於我以爲不須要爲處理極少會出現的錯誤場景而去浪費性能,影響用戶體驗。只要咱們作好兜底,即便這種錯誤狀況萬一真的出現,整個系統也不會所以出問題,仍是會正常使用。

寫在後面

小程序有不少的坑。目前市面上不少小程序性能體驗並非很好。因此爲了作一款高性能的小程序,是須要咱們花大量的時間去試錯,琢磨的。踩坑不止,生命不惜。

目前這一套 LRU 的文件存儲機制已經在咱們開源的 Painter 庫中使用,若有興趣請移步: github.com/Kujiale-Mob…

相關文章
相關標籤/搜索