天天看點

淺析前端緩存的應用,空間換時間

讀完這篇文章,我希望我可以給大家分享到的知識點

Vue.js 中那些空間換時間的操作

cache-loader的實作原理,緩存的應用

babel-loader,cacheDirectory=true時緩存的應用

浏覽器緩存

淺析前端緩存的應用,空間換時間
我們知道vue2.x是通過周遊對象的key去建立響應式對象的,如果一個對象足夠大,那麼遞歸周遊是非常耗時的
vue2.x中使用Object.defineProperty把對象變成響應式,一旦某個對象經過Object.defineProperty變成響應式對象後,會把響應式結果通過__ob__存儲起來,這樣一來,同樣的對象如果再次執行observe,則從緩存的__ob__中直接拿到對應的響應式值并傳回
vue對data進行處理,initState => initData => observe => 建立Observer對象 => def(value, 'ob', this)通過執行 def 函數把自身執行個體添加到資料對象 value 的 ob 屬性上
在談keep-alive前,先聊一個算法LRU,LRU是最近最少使用頁面置換算法(Least Recently Used),也就是首先淘汰最長時間未被使用的頁面!

新資料插入到連結清單頭部

每當緩存命中(即緩存資料被通路),則将資料移到連結清單頭部

當連結清單滿的時候,将連結清單尾部的資料丢棄

淺析前端緩存的應用,空間換時間
keep-alive實作了vue的元件執行個體緩存,2.x和3.0的實作政策一緻,都是對LRU緩存政策的應用,可以去看下源碼實作

vue2.x源碼在vue/src/core/components/keep-alive.js

vue3.0源碼在vue-next-master/packages/runtime-core/src/components/KeepAlive.ts

我們都知道.vue檔案中的template是通過vue-template-compiler進行ast轉換的,然而編譯是非常耗時的,如果每次都重新分析ast,組裝render函數,性能肯定大大降低,是以在設計的時候也用到了緩存,以空間換時間,達到了渲染優化的效果,這裡以2.x版本為例

cache-loader

webpack編譯時優化,cache-loader是一個很好的應用,cache-loader作為webpack的loader,會在pitch和loader兩個階段分别做一些事情:

pitch階段:校驗緩存檔案是否可用

loader階段:判斷目前loader的檔案是否需要重新生成緩存

webpack再次編譯時,根據目前正在處理的檔案,嘗試讀取.cache目錄中對應的cache檔案,處理目前檔案以及是以來的檔案,比較目前檔案與上一次loader的産物
判斷目前檔案是否需要重新生成緩存,判斷邏輯:如果pitch階段的判斷目前檔案的緩存失效了,那麼loader階段就要去生成緩存

babel-loader緩存的應用

webpack配置中使用babel-loader解析源碼時可以配置cacheDirectory=true來開啟緩存,執行babel-loader中定義的cache方法
cache方法的核心實作在handleCache中,實作原理和cache-loader類似,嘗試讀取緩存,存在就傳回,否則繼續建立緩存目錄,通過babel.transform轉譯代碼,執行gzip壓縮并寫入緩存

service worker

memory cache

disk cache

push cache

Expires

用來指定資源到期的時間,是服務端的具體時間點,Expires 是 HTTP/1 的産物,受限于本地時間,如果修改了本地時間,可能會造成緩存失效

Cache-Control

已知Expires的缺點之後,在HTTP/1.1中,增加了一個字段Cache-control,Cache-Control的優先級高于Expires,該字段表示資源緩存的最大有效時間,在該時間内,用戶端不需要向伺服器發送請求,與Expires的差別就是前者是絕對時間,而後者是相對時間

指令

作用

public

響應可以由任何緩存存儲,即使響應通常是不可緩存的

private

響應可能僅由浏覽器的緩存存儲,即使響應通常是不可緩存的

no-cache

響應可以由任何緩存存儲,即使響應通常是不可緩存的。但是,在使用存儲的響應之前,必須首先通過源伺服器的驗證,是以,不能将no cache與immutable結合使用

no-store

響應不能存儲在任何緩存中

max-age=<seconds>

資源被認為是新鮮的最長時間。與Expires不同,此指令與請求的時間有關

s-maxage=<seconds>

作用同max-age

max-stale=<seconds>

訓示用戶端将接受過時的響應。以秒為機關的可選值表示用戶端将接受的過期上限

min-fresh=<seconds>

訓示用戶端希望響應至少在指定的秒數内保持新鮮

stale-while-revalidate=<seconds>

訓示用戶端将接受過時響應,同時在背景異步檢查新響應

stale-if-error=<seconds>

訓示如果對新響應的檢查失敗,用戶端将接受過時的響應

must-revalidate

訓示一旦資源變為過時,如果未在源伺服器上成功驗證,緩存就不能使用其過時副本

proxy-revalidate

必須重新驗證,但僅限于共享緩存(例如代理)

immutable

訓示響應主體不會随時間而更改

no-transform

中間緩存或代理無法編輯響應正文、内容編碼、内容範圍或内容類型

only-if-cached

由用戶端設定,以訓示響應的“不使用網絡”

伺服器通過 Last-Modified 字段告知用戶端,資源最後一次被修改的時間,例如

Last-Modified: Mon, 10 Nov 2018 09:10:11 GMT

浏覽器将這個值和内容一起記錄在緩存資料庫中

下一次請求相同資源時時,浏覽器從自己的緩存中找出“不确定是否過期的”緩存。是以在請求頭中将上次的 Last-Modified 的值寫入到請求頭的 If-Modified-Since 字段

伺服器會将 If-Modified-Since 的值與 Last-Modified 字段進行對比。如果相等,則表示未修改,響應 304;反之,則表示修改了,響應 200 狀态碼,并傳回資料

缺陷:

如果資源更新的速度是秒以下機關,那麼該緩存是不能被使用的,因為它的時間機關最低是秒。

如果檔案是通過伺服器動态生成的,那麼該方法的更新時間永遠是生成的時間,盡管檔案可能沒有變化,是以起不到緩存的作用

Etag 存儲的是檔案的特殊辨別(一般都是 hash 生成的),伺服器存儲着檔案的 Etag 字段。之後的流程和 Last-Modified 一緻,隻是 Last-Modified 字段和它所表示的更新時間改變成了 Etag 字段和它所表示的檔案 hash,把 If-Modified-Since 變成了 If-None-Match。伺服器同樣進行比較,命中傳回 304, 不命中傳回新資源和 200。
Etag 的優先級高于 Last-Modified

強緩存優先于協商緩存

協商緩存失效,傳回200,重新傳回資源和緩存辨別

協商緩存生效,傳回304,繼續使用緩存

頻繁變動的資源

不常變動的資源

繼續閱讀