黑科技:LocalStorage 快取機制

發表於 2018-03-09
localStorage

黑科技:LocalStorage 快取機制

事情的起因是我的同事金果問我:
– “你知道微信公眾號文章的渲染方式嗎?”

對此,我的反應是:
– “啊?”

金果繼續問:
– “控制檯的 Network 裡沒有發生任何請求,文章裡的內容是怎麼來的?”

說到這兒我好像大概理解她的意思,於是開啟控制檯的 Network 確認一下果真如此,文章中的內容並不是通過 http 請求獲取的。

1460000013480585

首先我想到的是:
– “會不會是伺服器端渲染的?”

於是我找到請求得到的 html 檔案卻發現:

– “只有文章的標題是伺服器端渲染的,那麼文章的內容就只能在 js 檔案中。”

我繼續尋找請求得到的 js 檔案卻發現空空如也:
– “難道 js 檔案都被快取到 localStorage 裡?!”

1460000013480586

看到 Local Storage 裡密密麻麻的 js 檔案我心裡一陣澎湃:這確實是一種可以嘗試的前端載入效能優化的方式。

1460000013480587

使用 localStorage 進行資源快取的解決方案梳理

快取更新機制

專案在迭代開發的過程中,難以避免需要更新資原始檔,常用的方法有檔名${md5}.js或者在資源 url 後面加上特定字尾的方式 etc.,而在微信做法中以 __MOON__pages/report.js 為例,其版本資訊使用 key 為 __MOON__pages/report.js_ver 的儲存項儲存:

我們不直接使用這個 value 動態插入 script 節點來載入該檔案,而是根據後端提供的配置資訊,判斷是選擇使用快取的 __MOON__pages/report.js 檔案,還是重新發起載入請求。

搭建更新程式碼的腳手架

(載入 combo 化)使用基於 localStorage 的快取機制,就需要一個腳手架來管理資原始檔的讀取和寫入,不難看出微信使用的是自己開發的腳手架 moon.js,閱讀其原始碼代價較大,暫不分析。

資源配置資訊

前端在進行資源更新時需要後端提供一份依據供前端用於判斷哪些資源需要更新,並且腳手架 moon.js 需要該資源配置資訊才能正常工作,所以配置資訊一定要在 moon.js 的 script 標籤前輸出:

存在 XSS 安全隱患

__MOON__pages/report.js 檔案的入口處加入程式碼 alert(‘Helo World’); 如圖所示:

1460000013480588

重新整理頁面後彈出提示 “Hello World”,說明使用基於 localStorage 的快取機制存在一些安全隱患,並且微信尚未對這些攻擊漏洞進行處理。

1460000013480589

關於使用 localStorage 進行資源快取其他思考

  1. 如果先輸出 html 然後用 js 從本地快取讀取樣式再插入會出現嚴重的阻塞和閃爍問題
  2. 這種解決方案更加適合單頁面應用否則容易產生冗餘
  3. 存在瀏覽器相容性問題(隱身模式 etc.)(微信具有自己的X5核心完美解決該問題)
  4. 網路速度快,協商快取的響應延遲可能比 LS讀取+eval 更小
  5. 瀏覽器對於單次 set 和對 LS(本質是 SQL lite)的總容量存在限制
  6. 可以節省流量,並且可以用於 A/B test
  7. 移動端的瀏覽器快取經常會被清理且網路狀態通常較差,更加適合這種解決方案

https://github.com/scrat-team…
https://github.com/mtjs/mt

最後突然想起一句話:不要指望程式碼能解決一切問題。