為了解決小程序生成分享到朋友圈圖片的問題,我們開啟了 畫家計劃--- 一個小程序圖片生成庫。該計劃已開源,可移步: github.com/Kujiale-Mob… 。 大家知道 Canvas 的繪制有很多很蛋疼的坑,其中一個是它的 drawImage 方法,該方法在 IDE 中可以直接設置為網絡圖片的 url 進行繪制,但在真機上無法這樣做。有這個坑后,我們就需要先把圖片通過 download 下載到本地后,才能進行繪制。所以你的小程序中,如果有頻繁繪制一些圖片的需求,而又需要用到網絡圖片素材,這就導致每次繪制都要重新下載素材圖片,產生很大的繪制性能問題。 小程序本身是未提供文件 LRU 之類的緩存機制的。為了讓我們的 畫家計劃 圖片生成的更快,我們自己開發了的小程序文件進行 LRU 存儲的相關代碼。這樣我們就無需重復下載可能會頻繁使用到的繪圖素材,大大增加了繪圖速度。 介紹下小程序的緩存系統小程序的緩存分為數據緩存,和文件緩存兩部分。而文件緩存又分為臨時文件緩存,和本地文件存儲。其中本地文件存儲的大小限制為 10M。 數據緩存我們可以使用小程序提供的一套異步和同步的方法來增刪查結構化數據。同一個微信用戶,同一個小程序的存儲上限為 10MB。如果空間不足時會在小程序級別進行 LRU,也就是不經常使用的小程序的數據緩存區域會被全部清空。 詳細見微信官方文檔: developers.weixin.qq.com/miniprogram… 注:數據緩存區在體驗版、開發版、和線上版都共用一套,并不會隔離。文件臨時緩存我們在調用 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 兜底,所以即使這種情況出現,也不會影響用戶正常使用。只是會影響一點用戶體驗(畢竟一下子沒有以前的緩存了)。 注:之所以不像保證第二種情況的方式來保證第一種情況,是因為我覺得不需要為處理極少會出現的錯誤場景而去浪費性能,影響用戶體驗。只要我們做好兜底,即使這種錯誤情況萬一真的出現,整個系統也不會因此出問題,還是會正常使用。 寫在后面小程序有很多的坑。目前市面上很多小程序性能體驗并不是很好。所以為了做一款高性能的小程序,是需要我們花大量的時間去試錯,琢磨的。踩坑不止,生命不惜。 |