瀏覽器緩存簡單梳理

緩存知識適合所有js html css img等

是否已經(jīng)存在于用戶的緩存中,得知有哪些緩存,順序是什么

瀏覽器尋找的以次順序是:

1.內(nèi)存緩存
2.Service Worker緩存
3.HTTP 緩存
4.HTTP/2 push 緩存

內(nèi)存緩存

但是像“短期內(nèi)存緩存”這樣的名稱可能更合適:內(nèi)存緩存僅在導(dǎo)航結(jié)束之前保留資源,在某些情況下,甚至更少。

(link rel=preload)是預(yù)加載資源存儲在內(nèi)存緩存中的另一大案例。

但是,內(nèi)存緩存不會輕易地為請求提供匹配的資源。顯然,為了使請求和資源匹配,它們必須具有匹配的URL。但是,這還不夠。它們還必須具有匹配的資源類型(因此作為腳本提取的資源不能與圖像請求匹配),CORS模式和一些其他特征。

來自內(nèi)存緩存的請求的匹配特性在規(guī)范中沒有明確定義,因此可能在瀏覽器實現(xiàn)之間略有不同。
Memory Cache不關(guān)心的一件事是HTTP語義。如果存儲在其中的資源具有max-age=0或no-cache Cache-Control標(biāo)頭,那么這不是Memory Cache所關(guān)心的。由于它允許在當(dāng)前導(dǎo)航中重用資源,因此HTTP語義在這里并不重要。

Service Worker緩存

緩存是持久的,比memory cache生命周期長 。
從某種程度上說,它是不可預(yù)測的,只能遵守他們的主人,Web開發(fā)人員告訴他們的內(nèi)容。
首先,只有在頁面安裝了Service Worker時才存在。由于它的邏輯是由Web開發(fā)人員使用JavaScript定義的,而不是內(nèi)置到瀏覽器中。

Service Worker具有緩存API,使其能夠保留資源。它與Memory Cache之間的一個主要區(qū)別在于它是持久的。

需要額外寫Service Worker的代碼。緩存不會失效,除非開發(fā)人員寫的代碼明確刪除。

如果瀏覽器的存儲空間不足,則會出現(xiàn)另一種情況,在這種情況下, 整個 Service Worker緩存以及所有其他原始存儲(例如indexedDB,localStorage等)都會被破壞。這樣,Service Worker就可以知道該緩存中的資源在它們之間以及與其他原始存儲器同步。

服務(wù)工作者負(fù)責(zé)某個范圍,最多只限于一個主機。因此,服務(wù)工作者只能響應(yīng)對該范圍內(nèi)文檔請求的請求。

Service worker 緩存的好處是可以不需要服務(wù)端配合,但是service work必定no-store。

思考:Service Worker可以更復(fù)雜和細(xì)粒度的控制緩存以編程的形式。所以manifest cache就被淘汰了,相比之下兩者都能達到相同的功能但Service Worker靈活度更高。

example:

const version = '2';

self.addEventListener('install', event => {
  event.waitUntil(
    caches.open(`static-${version}`)
      .then(cache => cache.addAll([
        '/styles.css',
        '/script.js'
      ]))
  );
});

self.addEventListener('activate', event => {
  // …delete old caches…
});

self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request)
      .then(response => response || fetch(event.request))
  );
});

擴展閱讀caching best practices

服務(wù)工作者最好是作為一種增強而不是解決方法,所以不要使用緩存,而是使用它!

HTTP 緩存

HTTP緩存通過HTTP Header來描述緩存邏輯。

強緩存

實現(xiàn)強緩存可以通過兩種響應(yīng)頭實現(xiàn):Expires 和 Cache-Control。強緩存表示在緩存期間不需要請求,state code為200。

Expires 是 HTTP / 1.0 的產(chǎn)物,表示資源會在 Wed, 22 Oct 2018 08:41:00 GMT 后過期,需要再次請求。并且 Expires 受限于本地時間,如果修改了本地時間,可能會造成緩存失效。

Expires: Wed, 22 Oct 2018 08:41:00 GMT

Cache-Control 出現(xiàn)于 HTTP / 1.1,優(yōu)先級高于 Expires 。該屬性表示資源會在 30 秒后過期,需要再次請求。

Cache-Control: max-age=30

優(yōu)先使用Cache-Control, Cache-Control部分字段解釋:

  • max-age=<seconds> 該屬性表示資源會在seconds秒后過期,需要再次請求。
  • no-store 緩存不應(yīng)存儲有關(guān)客戶端請求或服務(wù)器響應(yīng)的任何內(nèi)容。如果是Service Worker緩存的,建議使用。
  • no-cache 表示必須先與服務(wù)器確認(rèn)返回的響應(yīng)是否發(fā)生了變化,然后才能使用該響應(yīng)來滿足后續(xù)對同一網(wǎng)址的請求。因此,如果存在合適的驗證令牌 (ETag),no-cache 會發(fā)起往返通信來驗證緩存的響應(yīng)(例如If-None-Match或If-Modified-Since),但如果資源未發(fā)生變化,則可避免下載。
  • immutable 表示響應(yīng)正文不會隨時間變化。資源(如果未過期)在服務(wù)器上未更改,因此客戶端不應(yīng)為其發(fā)送條件重新驗證(例如If-None-Match或If-Modified-Since)以檢查更新,即使用戶明確刷新頁面也是如此。通常在https中實現(xiàn)。
  • public 表示任何緩存都可以緩存響應(yīng)。即使它有關(guān)聯(lián)的HTTP身份驗證,甚至響應(yīng)狀態(tài)代碼通常是無法緩存,最終也可以緩存響應(yīng)。大多數(shù)情況下,“public”不是必需的,因為明確的緩存信息(例如“max-age”)已表示響應(yīng)是可以緩存的。
  • private 瀏覽器可以緩存“private”響應(yīng)。不過,這些響應(yīng)通常只為單個用戶緩存,因此不允許任何中間緩存對其進行緩存。例如,用戶的瀏覽器可以緩存包含用戶私人信息的 HTML 網(wǎng)頁,但 CDN 卻不能緩存。

immutable的推薦用法是和那些超大的 max-age 配合使用,比如 1年:Cache-Control: max-age=31536000, immutable,甚至 10年, 但通常情況下,1 年就夠了,因為:1. 對于單個緩存來說,它在某個瀏覽器里存活的時長不可能超過一年,瀏覽器的緩存空間都有上限,F(xiàn)irefox 256M,Chrome 320M,舊的緩存會時不時被清掉。

immutable并不是真的只能應(yīng)用在那些永不過期的資源上,也可以配合較小的 max-age 來使用,比如一些個人博客,或者一些不太講究及時更新的站點,可以設(shè)置成 Cache-Control: max-age=3600, immutable,表明該資源能存活一小時,在一小時之內(nèi),即便用戶刷新也不要發(fā)送條件請求。這里需要注意,一旦被標(biāo)志成 immutable,則這個資源不可能返回 304 響應(yīng)了,只有 200。

Cache-Control參考鏈接

協(xié)商緩存

協(xié)商緩存,如果緩存過期了,我們就可以使用協(xié)商緩存來解決問題。協(xié)商緩存需要請求,如果緩存有效會返回 304。

協(xié)商緩存需要客戶端和服務(wù)端共同實現(xiàn),和強緩存一樣,也有兩種實現(xiàn)方式。

  • Last-Modified和If-Modified-Since。Last-Modified表示文件最后修改日期。If-Modified-Since會將Last-Modified的值發(fā)送給服務(wù)器,詢問是否有更新,有更新則將新資源發(fā)送回來。如果本地打開緩存文件,就會造成Last-Modified被修改
  • ETag和If-None-Match。If-None-Match會將當(dāng)前ETag(相當(dāng)于指紋)發(fā)送給服務(wù)器,詢問是否變動,如果有就發(fā)送新資源發(fā)送回來。ETag優(yōu)先級大于Last-Modified。

注意 在任何資源上禁止頭部 Last-Modified 都會導(dǎo)致一個 If-Modified-Since 條件查詢,即使資源在緩存中。與 Etag 一樣,即使它在使用中。

緩存策略

  • 對于某些不需要緩存的資源,可以使用 Cache-control: no-store ,表示該資源不需要緩存。
  • 對于頻繁變動的資源,可以使用 Cache-Control: no-cache 并配合 ETag 使用,表示該資源已被緩存,但是每次都會發(fā)送請求詢問資源是否更新。
  • 對于代碼文件來說,通常使用 Cache-Control: max-age=31536000 并配合策略緩存使用,然后對文件進行指紋處理,一旦文件名變動就會立刻下載新的文件。如style.x234diff.css
image.png

如果多個頁面,都使用相同的資源,我們可以相同的域名和文件名使其達到共享緩存的作用。

緩存檢查清單

不存在什么最佳緩存策略。您需要根據(jù)通信模式、提供的數(shù)據(jù)類型以及應(yīng)用特定的數(shù)據(jù)更新要求,為每個資源定義和配置合適的設(shè)置,以及整體的“緩存層次結(jié)構(gòu)”。

在制定緩存策略時,您需要牢記下面這些技巧和方法:

  • 使用一致的網(wǎng)址:如果您在不同的網(wǎng)址上提供相同的內(nèi)容,將會多次獲取和存儲這些內(nèi)容。提示:請注意,網(wǎng)址區(qū)分大小寫。
  • 確保服務(wù)器提供驗證令牌 (ETag):有了驗證令牌,當(dāng)服務(wù)器上的資源未發(fā)生變化時,就不需要傳送相同的字節(jié)。
  • 確定中間緩存可以緩存哪些資源:對所有用戶的響應(yīng)完全相同的資源非常適合由 CDN 以及其他中間緩存進行緩存。
  • 為每個資源確定最佳緩存周期:不同的資源可能有不同的更新要求。為每個資源審核并確定合適的 max-age。
  • 確定最適合您的網(wǎng)站的緩存層次結(jié)構(gòu):您可以通過為 HTML 文檔組合使用包含內(nèi)容指紋的資源網(wǎng)址和短時間或 no-cache 周期,來控制客戶端獲取更新的速度。
  • 最大限度減少攪動:某些資源的更新比其他資源頻繁。如果資源的特定部分(例如 JavaScript 函數(shù)或 CSS 樣式集)會經(jīng)常更新,可以考慮將其代碼作為單獨的文件提供。這樣一來,每次獲取更新時,其余內(nèi)容(例如變化不是很頻繁的內(nèi)容庫代碼)可以從緩存獲取,從而最大限度減少下載的內(nèi)容大小。

擴展閱讀Heroku的HTTP緩存頭部

比如Vue Cli3的創(chuàng)建的模板項目中的web server就提供了上述緩存功能,尤其是生出的dist目錄下的文件都帶了指紋(app.06f96ef0.js)。

HTTP/2 Push緩存

Push緩存(更好地描述為“無人認(rèn)領(lǐng)的推送流容器”,但名稱不那么吸引人)是存儲HTTP / 2推送資源的地方。它們存儲為HTTP / 2會話的一部分,具有多種含義。

容器沒有持久性。如果會話終止,則所有未聲明的資源(即與其請求不匹配)都將消失。如果使用不同的HTTP / 2會話獲取資源,則不會匹配。最重要的是,資源僅在有限的時間內(nèi)保留在推送緩存容器中。(在基于Chromium的瀏覽器中約5分鐘)

Push緩存根據(jù)其URL以及其各種請求標(biāo)頭匹配對資源的請求,但它不應(yīng)用嚴(yán)格的HTTP語義。

Push緩存在規(guī)范中也沒有明確定義,并且實現(xiàn)可能因瀏覽器,操作系統(tǒng)和其他HTTP / 2客戶端而異。

由于可以在多個選項卡之間重復(fù)使用 HTTP/2 連接,所以推送的資源也可以被來自其他選項卡的請求聲明.

目前,服務(wù)器并沒有一個簡單的方法得知被推送的資源 是否已經(jīng)存在于用戶的緩存中,因此每個用戶的訪問都會繼續(xù)推送資源。因此,您可能需要創(chuàng)建一個緩存監(jiān)測 HTTP/2 服務(wù)器推送機制(通過服務(wù)器加cookie來確定)。如果被提取,您可以嘗試從緩存中獲取它們,這樣可以避免再次推送。但請記住,新的cache-digest規(guī)范無需手動建立這樣的 “緩存感知” 的服務(wù)器

介紹:cache-digest 緩存摘要

Cache Digest是IETF HTTP工作組目前正在討論的規(guī)范。11請注意,規(guī)范正在進行更改,如果它完全通過標(biāo)準(zhǔn)軌道,那么您在此處閱讀的內(nèi)容可能無法反映最終標(biāo)準(zhǔn)??蛻舳藢⒕彺嬲l(fā)送到服務(wù)器。它告訴服務(wù)器客戶端的緩存包含什么。知道哪些資產(chǎn)已經(jīng)或者沒有被客戶端緩存的服務(wù)器可以準(zhǔn)確地推送所需的內(nèi)容。

最后,可以想象以下情況,某些資源客戶端是一定會請求的,這時就可以采取服務(wù)端 push 的技術(shù),提前給客戶端推送必要的資源,這樣就可以相對減少一點延遲時間。當(dāng)然在瀏覽器兼容的情況下你也可以使用preload/prefetch。擴展閱讀http2-push-vs-http-preload

是否要使用push cashe呢,可以參考Should I Push。

思考:目前看起來使用Push緩存難度有點大,性價比不高。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容