瀏覽器緩存之http緩存和service worker

相關代碼下載地址:https://download.csdn.net/download/u010674395/12555506

一、什麼是瀏覽器緩存

以往談起性能優化,大部分時候都是從後端聊起,數據庫的設計,緩存的使用等。其實前端在性能優化方面可做的也很多,如:減少http請求數、使用cdn、壓縮合並css/js等,瀏覽器緩存就是把已經請求過的Web資源進行存儲,當用戶刷新頁面或者下次訪問時候,瀏覽器根據緩存機制決定是否需要向服務端發起請求。 所以緩存可以帶來:減少網絡帶寬消耗、降低服務器壓力、減少網絡延遲,加快頁面打開速度等優點

二、瀏覽器緩存有哪些

1、http緩存是基於HTTP協議的瀏覽器文件級緩存機制。

2、websql這種方式只有較新的chrome瀏覽器支持,並以一個獨立規範形式出現

3、indexDB 是一個爲了能夠在客戶端存儲可觀數量的結構化數據,並且在這些數據上使用索引進行高性能檢索的 API

4、Cookie一般網站爲了辨別用戶身份、進行session跟蹤而儲存在用戶本地終端上的數據(通常經過加密)

5、Localstorage是html5的一種新的本地緩存方案,目前用的比較多,一般用來存儲ajax返回的數據,加快下次頁面打開時的渲染速度

6、Sessionstorage和localstorage類似,但是瀏覽器關閉則會全部刪除,api和localstorage相同,實際項目中使用較少。

7、application cache 是將大部分圖片資源、js、css等靜態資源放在manifest文件配置中

8、cacheStorage是在ServiceWorker的規範中定義的,可以保存每個serverWorker申明的cache對象 今天重點說下http緩存和serviceworker

三、瀏覽器緩存存放的位置

通過上圖可發現: 瀏覽器緩存有一些資源存在了memory cache(內存中) 有一些資源存在了disk cache(磁盤中) 關掉頁面再重新請求,會是什麼樣?(自己實踐一下)

1、memory cache

按照操作系統的常理:先讀內存,再讀硬盤。幾乎所有的網絡請求資源都會被瀏覽器自動加入到 memory cache 中。但是也正因爲數量很大但是瀏覽器佔用的內存不能無限擴大這樣兩個因素,memory cache 註定只能是個“短期存儲”。常規情況下,瀏覽器的 TAB 關閉後該次瀏覽的 memory cache 便告失效 (爲了給其他 TAB 騰出位置)。而如果極端情況下 (例如一個頁面的緩存就佔用了超級多的內存),那可能在 TAB 沒關閉之前,排在前面的緩存就已經失效了。 memory cache 機制保證了一個頁面中如果有兩個相同的請求 (例如兩個 src 相同的 <img>,兩個 href 相同的 <link>)都實際只會被請求最多一次,避免浪費。 在從 memory cache 獲取緩存內容時,瀏覽器會忽視例如 max-age=0, no-cache 等頭部配置。 如果站長是真心不想讓一個資源進入緩存,就連短期也不行,那就需要使用 no-store。 思考:剛纔提到 幾乎所有的網絡請求資源都會被瀏覽器自動加入到 memory cache 中,爲什麼? preloader,在2007年之前,許多情況下,瀏覽器某些元素的解析和執行可能會影響緊隨其後的資源,瀏覽器停止並等待資源完成下載,然後再獲取下一個資源。這意味着如果一個頁面包含多個JavaScript資源或外部CSS資源,在它們之後的元素,解析器將暫停並等待每個外部資源完成下載,然後再獲取下一行內容。隨着頁面越來越繁瑣的JavaScript,對性能的影響是巨大的,並且是災難性的。所以在資源解析執行時候,網絡狀態是空閒的,能不能邊解邊請求資源呢,在2008年,ie/谷歌等瀏覽器便有了相關的機制(預加載器機制),預加載的資源都是放在memory cache中的。

2、disk cache

存儲在硬盤上的緩存會嚴格根據 HTTP 頭信息中的各類字段來判定哪些資源可以緩存,哪些資源不可以緩存;哪些資源是仍然可用的,哪些資源是過時需要重新請求的。當命中緩存之後,瀏覽器會從硬盤中讀取資源,雖然比起從內存中讀取慢了一些,但比起網絡請求還是快了不少的。絕大部分的緩存都來自 disk cache。 凡是持久性存儲都會面臨容量增長的問題,disk cache 也不例外。在瀏覽器自動清理時,每個瀏覽器都會識別“最老的”和“最可能過時的”資源。 HTTP 的協議頭中的緩存字段,我們稍後再說

3、Service Worker

Service Worker 是 Chrome 團隊提出和力推的一個 WEB API,用於給 web 應用提供高級的可持續的後臺處理能力。 service worker 能夠操作的緩存是有別於瀏覽器內部的 memory cache 或者 disk cache。它是獨立於當前頁面的一段運行在瀏覽器後臺進程裏的腳本。大家可以把 Service Worker 理解爲一個介於客戶端和服務器之間的一個代理服務器。在 Service Worker 中我們可以做很多事情,比如攔截客戶端的請求、向客戶端發送消息、向服務器發起請求等等,離線資源緩存只是它的作用之一。 這個緩存是永久性的,即關閉 TAB 或者瀏覽器,下次打開依然還在(而 memory cache 不是)。有兩種情況會導致這個緩存中的資源被清除:手動調用 API cache.delete(resource) 或者容量超過限制,被瀏覽器全部清空。 Service Worker 特點 網站必須使用 HTTPS。除了使用本地開發環境調試時(如域名使用 localhost) 運行於瀏覽器後臺,可以控制打開的作用域範圍下所有的頁面請求 單獨的作用域範圍,單獨的運行環境和執行線程 不能操作頁面 DOM。但可以通過事件機制來處理

4、Service Worker的註冊和安裝

if('serviceWorker' in navigator) {
    console.log('支持')
    window.navigator.serviceWorker
      .register('/sw.js', {
        scope: '/' // 作用域
      })
      .then(registration => {
        console.log('註冊成功', registration.update)  
      })
      .catch(error => {
        console.log('註冊失敗', error.message)
      })
  } else {
    console.log('不支持')
  }


self.addEventListener('install', event => {
    // event.waitUtil 用於在安裝成功之前執行一些預裝邏輯
    // 建議只做一些非常重要資源的緩存,減少安裝失敗的概率
    // 安裝成功後 ServiceWorker 狀態會從 installing 變installed
    event.waitUntil(
        // 使用 cache API 打開指定的 cache 文件
        caches.open('版本標識').then(cache => {
            console.log(cache);
            // 添加要緩存的資源列表
            return cache.addAll('要緩存的文件列表');
        })
    );
});

四、強制緩存

強制緩存的含義是,當客戶端請求後,會先訪問緩存數據庫看緩存是否存在。如果存在則直接返回;不存在則請求真的服務器,響應後再寫入緩存數據庫。 強制緩存直接減少請求數,是提升最大的緩存策略。如果考慮使用緩存來優化網頁性能的話,強制緩存應該是首先被考慮的。 可以造成強制緩存的字段是 Cache-control 和 Expires。 Expires是http1.0的字段,表示緩存到期時間,是一個絕對的時間。在響應消息頭中,設置這個字段之後,就可以告訴瀏覽器,在未過期之前不需要再次請求。 缺點:用戶更改客戶端時間就會造成失效。時間字符串多個空格等都會報錯(Expires: Thu, 10 Nov 2020 08:45:11 GMT) Cache-control是HTTP/1.1的字段,該字段表示資源緩存的最大有效時間,在該時間內,客戶端不需要向服務器發送請求。 這兩者的區別就是前者是絕對時間,而後者是相對時間。 Cache-control 的優先級高於 Expires,爲了兼容 HTTP/1.0 和 HTTP/1.1,實際項目中兩個字段可以都設置。

1、強制緩存之Cache-control的值

max-age:即最大有效時間

must-revalidate:如果超過了 max-age 的時間,瀏覽器必須向服務器發送請求,驗證資源是否還有效。

no-cache:雖然字面意思是“不要緩存”,但實際上還是要求客戶端緩存內容的,只是是否使用這個內容由後續的對比來決定。

no-store: 真正意義上的“不要緩存”。所有內容都不走緩存,包括強制和對比。

public:所有的內容都可以被緩存 (包括客戶端和代理服務器, 如 CDN)

private:所有的內容只有客戶端纔可以緩存,代理服務器不能緩存。默認值。

五、對比緩存 (協商緩存)

當強制緩存失效(超過規定時間)時,就需要使用對比緩存,由服務器決定緩存內容是否失效。

流程上說,瀏覽器先請求緩存數據庫,返回一個緩存標識。之後瀏覽器拿這個標識和服務器通訊。如果緩存未失效,則返回 HTTP 狀態碼 304 表示繼續使用,於是客戶端繼續使用緩存;如果失效,則返回新的數據和緩存規則,瀏覽器響應數據後,再把規則寫入到緩存數據庫。 對比緩存在請求數上和沒有緩存是一致的,但如果是 304 的話,返回的僅僅是一個狀態碼而已,並沒有實際的文件內容,因此 在響應體體積上的節省是它的優化點。它的優化體現在瀏覽器的“響應”上。通過減少響應體體積,來縮短網絡傳輸時間。所以和強制緩存相比提升幅度較小,但總比沒有緩存好。

對比緩存是可以和強制緩存一起使用的,作爲在強制緩存失效後的一種後備方案。實際項目中他們也的確經常一同出現。

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

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

瀏覽器將這個值和內容一起記錄在緩存數據庫中。

下一次請求相同資源時時,瀏覽器從自己的緩存中找出“不確定是否過期的”緩存。因此在請求頭中將上次的 Last-Modified 的值寫入到請求頭的 If-Modified-Since 字段 服務器會將 If-Modified-Since 的值與 Last-Modified 字段進行對比。如果相等,則表示未修改,響應 304;反之,則表示修改了,響應 200 狀態碼,並返回數據。

但是他還是有一定缺陷的: 如果資源更新的速度是秒以下單位,那麼該緩存是不能被使用的,因爲它的時間單位最低是秒。 如果文件是通過服務器動態生成的,那麼該方法的更新時間永遠是生成的時間,儘管文件可能沒有變化,所以起不到緩存的作用。

爲了解決上述問題,出現了一組新的字段 Etag 和 If-None-Match Etag 存儲的是文件的特殊標識(一般都是 hash 生成的),服務器存儲着文件的 Etag 字段。之後的流程和 Last-Modified 一致,只是 Last-Modified 字段和它所表示的更新時間改變成了 Etag 字段和它所表示的文件 hash,把 If-Modified-Since 變成了 If-None-Match。服務器同樣進行比較,命中返回 304, 不命中返回新資源和 200。

Etag 的優先級高於 Last-Modified

六、緩存小結

當瀏覽器要請求資源時 調用 Service Worker 的 fetch 事件響應 查看 memory cache 查看 disk cache。這裏又細分:     如果有強制緩存且未失效,則使用強制緩存,不請求服務器。這時的狀態碼全部是 200     如果有強制緩存但已失效,使用對比緩存,比較後確定 304 還是 200 發送網絡請求,等待網絡響應 把響應內容存入 disk cache (如果 HTTP 頭信息配置可以存的話) 把響應內容 的引用 存入 memory cache (無視 HTTP 頭信息的配置) 把響應內容存入 Service Worker 的 Cache Storage (如果 Service Worker 的腳本調用了 cache.put())

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章