關於緩存和 Chrome 的「新版刷新」

在讀本文前你要確保讀過個人上篇文章《扼殺 304,Cache-Control: immutable》,由於本文是接着上文寫的。上文說到,在現代 Web 上,「條件請求/304 響應」絕大多數都是浪費資源,由於絕大多數靜態資源都是永恆不變的,所以 Firefox 實現了 Cache-Control: immutable 來讓開發者們控制用戶瀏覽器的刷新行爲,即在刷新時不要對這些資源文件進行條件請求(緩存不過時的前提下)。html

Chrome 至今遲遲沒有實現 Cache-Control: immutable,難道 Chrome 不想讓本身的網頁在刷新時展示的更快?不是的,其實 Chrome 的開發人員也早已注意到了這個問題。早在 2015 年末,他們就開發出了一種新的刷新行爲,稱之爲 new reload/faster reload/non-validating reload,這種新的刷新和之前傳統的刷新有個區別,那就是在刷新頁面時,只對頁面自己的資源文件進行條件請求(若是緩存了的話),頁面裏引用的各類子資源文件,只要緩存不過時,就直接讀取緩存。也就是說,「大家開發者壓根不用去加什麼 Cache-Control: immutable 響應頭了,我 Chrome 直接改爲刷新不發條件請求就得了」。前端

Chrome 在 2015 年末只針對安卓端的 Chrome for Android 中的下拉刷新開啓了這種新的刷新,下面是當時的 commit logchrome

Make pull to refresh not perform regular reload (with cache revalidation)瀏覽器

Pull-to-refresh action on Android is currently handled as a
regular reload, which causes revalidation of cached contents,
however the action would usually imply that the user wants to
refresh the 'contents' rather than reloading everything (e.g.
to reset the page contents when something's screwed up).緩存

這段話中說到,用戶刷新一個頁面一般都不是爲了從新請求每一個資源文件看是否是過時了,而僅僅是爲了重置一下頁面的狀態,因此要作這個優化。下面是當時測試效果的對比演示,左舊右新:服務器

 

能夠看到,左側有明顯的加載白屏階段,而右側沒有。cookie

在 16 年 5 月份,Chrome 把該刷新行爲應用到了 PC 端,從 Chrome 54 開始默認啓用。我寫了一個測試 demo,在 Chrome 54 以前,刷新這個 demo 後效果是這樣的:網絡

全部的資源都會被髮起條件請求從而返回 304 響應,而在 Chrome 54 裏,刷新這個 demo 後效果成了:ide

只有頁面自己被髮起了條件請求,全部引用的子資源都直接讀取了緩存,也就是說,實際上刷新這個頁面只觸發了一個 HTTP 請求。 工具

額外小技巧

從 Chrome 56 開始,你能夠經過網絡面板新增的 is:from-cache 過濾條件來過濾出直接讀取緩存的請求(即沒有發送真實的 HTTP 請求的請求),還能夠利用它的反向過濾找出發送了真實請求的請求,像下面這樣(仍是上面的 demo):

這個過濾條件是我向 Chrome 提議的。

不知道大家注意過沒有,除刷新外,常規加載一個網頁的途徑有兩種,最多見的一種是經過點擊其餘頁面的超連接(包括瀏覽器書籤)進入當前頁面,還有一種是在瀏覽器地址欄上輸入網址並回車(高級用戶),這二者在發送請求上也是有區別的。前者是不會發起任何條件請求的(除非緩存過時),然後者是會爲頁面資源自己發起條件請求的(你能夠用上面的 demo 作測試),Chrome 新的這個刷新機制其實就是把刷新改得和在地址欄回車同樣了。鑑於現現在的大多頁面都是動態頁面(沒有 Cache-Control/Expires/Last-modified 響應頭),不會被緩存,因此現在這三者在 Chrome 上的差異已經很小了。

若是你已經升級到了 Chrome 的最新版,無法找到 Chrome 54 以前的版原本作對比測試,能夠試試經過停用 chrome://flags/#enable-non-validating-reload-on-normal-reload 選項來切回老版的刷新,不過這個選項在 Chrome 56 裏已經被完全刪除了:

讀到這裏,有同窗就想問了,「難道 Chrome 這樣作不違反 HTTP 協議嗎?」。並無,HTTP 協議只會規定客戶端應該怎麼發一個條件請求,服務器應該怎麼響應這個條件請求,但不會規定應用程序什麼時候應該發送條件請求。

那 location.reload() 呢,也會改爲新版刷新嗎?從 Chrome 56 開始 location.reload() 也會使用新版刷新。HTML 規範並無明確的說明 location.reload() 應該如何對待緩存,只略略提到了一句:

User agents may allow the user to explicitly override any caches when reloading.

這句話應該是給 Firefox 的 location.reload(true) 準備的。

那對用戶來講,這個改動向後兼容嗎?從我注意到 Chrome 的這個改動後,一直覺得這是 Chrome 的 bug,但提 bug 後被告知這是有意的。我當時覺的這個改動太激進了,畢竟打破了二十年多年的瀏覽器傳統,必定會有用戶反饋不兼容問題的。但直到這個改動進入穩定版後,也沒有一我的反饋。。。彷彿全世界只有我一我的注意到了這個改動。

但對開發者來講,其實這個改動的確是有點不向後兼容的。好比某個帶有特定版本號的資源在發佈到 daily 環境後,是能夠不換版本號(URL)反覆覆蓋式更新的,但你在瀏覽器裏刷新卻看不到效果,只能藉助於開發者工具的 Disable cache 功能。不過最終用戶是沒這個問題的,由於線上是沒法覆蓋式發佈的。

因此如今個人見解變了,Firefox 和其餘瀏覽器應該變的像 Chrome 同樣,Cache-Control: immutable 已經幾乎沒有價值了(除非我漏掉了某個點),能讓全部的網頁變的更快,爲何不呢。

俗話說的好,「前端有三寶,清緩存、清 cookie、換個瀏覽器」。之後在 Chrome 裏單純的刷新是真的不行了,要教用戶怎麼「強制刷新/跳過緩存刷新」了。

能夠看到本身公司 CDN 日誌的同窗們,能夠看看最近 304 響應的佔比有沒有大幅減小,不過國內的話也許須要等國產瀏覽器的內核更新後才行。

相關文章
相關標籤/搜索