前言
這里討論的緩存包括兩種,一種是HTTP緩存,一種是Service Worker緩存。
HTTP緩存
HTTP緩存應該是最傳統的方式,也是所有前端項目的基礎。瀏覽器向服務器請求數據,發送請求(request)報文;服務器向瀏覽器返回數據,返回響應(response)報文。我們熟悉的瀏覽器緩存機制可以被分為兩大類:強緩存和協商緩存。強緩存主要包括Cache-Control和Expires,協商緩存主要包括Etag和Last-Modify。協商緩存優先級是優先于強緩存。js等大部分靜態資源在做了文件指紋后,都使用強緩存的策略。而html文件是頁面入口和文件名不能修改比較特殊,大部分都采用協商緩存。
強緩存
Cache-Control
一般js,css和圖片等靜態資源文件采用強緩存的機制,保證資源在某個時間段內在命中的情況下從緩存機制中獲取。
稍微了解HTTP協議的前端同學,想必對Cache-Control不會感到陌生,性能優化時經常都會跟它打交道,屬于HTTP 1.1。常見的值有有private、public、no-store、no-cache、must-revalidate、max-age等。
- no-cache: 不管本地副本是否過期,使用資源副本前,強制回源服務器進行副本有效性校驗。
- must-revalidate:本地副本過期前可以使用本地副本;本地副本一旦過期,必須去源服務器進行有效性校驗。
Expires
Expires的值為服務端返回的到期時間,即下一次請求時,請求時間小于服務端返回的到期時間,直接使用緩存數據。這樣會帶來一個問題,就是服務器時間和客戶端時間不一致的情況,現在網頁都是全球化的,會造成不同時區的用戶訪問更新不一致。Expires 是HTTP 1.0的東西,現在默認瀏覽器均默認使用HTTP 1.1。
協商緩存
Etag
協商緩存(又名對比緩存)由服務器來確定緩存資源是否可用,所以客戶端與服務器端要通過某種標識來進行通信,從而讓服務器判斷請求資源是否可以緩存訪問。而Etag就是這個標示,屬于HTTP1.1的標準。如果命中協商緩存會返回304,如果未命中會從服務器取數據返回200。它和Last-Modify最大的區別就是,Last-Modify專注某個時間點。這個和Expires犯了同樣的錯誤。協商緩存整個流程如下圖,它必須和服務器有一次交互,一般html的檢查是否更新,就是這樣完成。一般像JS和CSS都是帶hash值,保證文件唯一性,控制緩存。
為什么需要Etag?
- 一些文件也許會周期性的更改,但是他的內容并不改變(僅僅改變的修改時間),這個時候我們并不希望客戶端認為這個文件被修改了,而重新GET;
- 某些文件修改非常頻繁,比如在秒以下的時間內進行修改,(比方說1s內修改了N次),If-Modified-Since能檢查到的粒度是s級的,這種修改無法判斷(或者說UNIX記錄MTIME只能精確到秒);
- 某些服務器不能精確的得到文件的最后修改時間。
如果你使用協商緩存,第一次加載返回200狀態碼,加載速度較慢,數據量大。第二次加載返回304狀態碼,加載速度較快,數據量小。這也是為什么我們第二次加載速度比較快,第一次加載比較慢。此外,協商緩存和網速有強相關性,網速慢的情況下,頁面加載速度也會很慢。
Last-Modify
Last-Modify記錄的是指上次代碼更新的時間。上次更新的時間和客戶端當前時間的對比,決定了協商緩存是否執行。
強緩存和協商緩存的對比
強緩存和協商緩存其實都是為了解決非首次加載后的緩存問題。協商緩存可以保證渠道的靜態資源是最新內容。
緩存類型 | 狀態碼 | 發送請求到服務器 |
---|---|---|
強緩存 | 200(from cache) | 否,直接從緩存取 |
協商緩存 | 304(Not Modified) | 否,通過服務器來告知緩存是否可用 |
用戶操作 | Expires/Cache-Control | Last-Modied/Etag |
---|---|---|
地址欄回車 | 有效 | 有效 |
頁面鏈接跳轉 | 有效 | 有效 |
新開窗口 | 有效 | 有效 |
前進回退 | 有效 | 有效 |
F5刷新 | 無效 | 有效 |
Ctrl+F5強制刷新 | 無效 | 無效 |
在實際使用的過程當中,緩存的策略可以通過nginx或者cdn運營商配置對應的緩存策略。如今應該各種大廠都有自建cdn來達到靜態資源加速的效果。
Service Worker緩存
但是HTTP的緩存每次生效嗎?在app強制關閉的情況下能控制緩存機制嗎?在弱網的情況下,協商緩存會和后端進行交互,還是影響頁面白屏時間。Service Worker緩存(簡稱SW緩存)就是用解決協商緩存的問題,并且給開發者提供了控制緩存的能力。如果你做的網頁可以被當成一個大型單頁面應用,這個應用需要一個manifest.json
來控制它基礎應用顯示信息,還需要以一個service-worker.js
來控制它的離線緩存信息。
HTTP以前的緩存機制是Network和application之間的交互,Service Worker緩存機制則是在它們之間加入一個代理層,優先取本地的資源,之后檢查數據內容是否更新。如果有更新,將會在下一次更新才更新數據內容。
因此,SW緩存也是pwa的基礎要素之一,詳情可見PWA筆記二:離線緩存原理。
WIFI 情況
3G情況
在網速弱網情況,協商緩存的情況會收到影響,因為它和網速是強相關的。而service-worker和網速時弱相關的,和單頁面網頁應用的屬性是天然契合的,幫助網頁應用更貼近native app。
參考
PS
shopee,又稱蝦皮,是一家騰訊投資的跨境電商平臺。這里加班少,技術氛圍好。如果想和我并肩作戰一起學習,可以找我內推。郵箱1542453460@qq.com,非誠勿擾。