<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          前端高級進階:網(wǎng)站的緩存控制策略最佳實踐及注意事項

          共 2674字,需瀏覽 6分鐘

           ·

          2020-03-10 23:25

          對于一個網(wǎng)站來講,性能關(guān)乎用戶體驗,你在更短的時間內(nèi)打開網(wǎng)站,你將會留住更多的用戶。如果你的頁面十秒才能打開,那再好的用戶交互也是徒然。

          8f57daffd26b4c6c71be3a7b3b1ab05e.webp

          緩存控制是網(wǎng)站性能優(yōu)化中至為常見及重要的一環(huán),好的緩存控制,除了使網(wǎng)站在性能方面有所提升,在財務(wù)方面也有重要提升: 更好的緩存策略意味著更少的請求,更少的流量,更少的峰值帶寬,從而節(jié)省一大筆服務(wù)器或者 CDN 的費用。

          緩存控制策略就是 http caching 的策略,化繁為簡,最有效的策略往往是很簡單的。在最簡單的粗略下,你對 http cache 只需要了解一個 Cache-Control 的頭部。

          一個較好的緩存策略只需要兩部分,而它們只需要通過 Cache-Control 控制:

          1. 帶指紋資源: 永久緩存
          2. 非帶指紋資源: 每次進行新鮮度校驗

          作圖如下:

          343bf20767b4a96edb03c3fbd7dc4a48.webp緩存控制策略

          帶指紋資源: 永久緩存

          Cache-Control: max-age=31536000

          天下武功,無堅不摧,唯快不破。資源請求最快的方式就是不向服務(wù)器發(fā)起請求,通過以上響應(yīng)頭可以對資源設(shè)置永久緩存。

          1. 靜態(tài)資源帶有 hash 值,即指紋
          2. 對資源設(shè)置一年過期時間,即 31536000,一般認為是永久緩存
          3. 在永久緩存期間瀏覽器不需要向服務(wù)器發(fā)送請求

          那為什么帶有 hash 值的資源可以永久緩存呢?

          因為該文件的內(nèi)容發(fā)生變化時,會生成一個帶有新的 hash 值的 URL。 前端將會發(fā)起一個新的 URL 的請求。

          非帶指紋資源: 每次進行新鮮度校驗

          Cache-Control: no-cache
          1. 由于不帶有指紋,每次都需要校驗資源的新鮮度。(從緩存中取到資源,可能是過期資源)
          2. 如果校驗為最新資源,則從瀏覽器的緩存中加載資源

          index.html 為不帶有指紋資源,如果把它置于緩存中,則如何保證服務(wù)器刷新數(shù)據(jù)時,被瀏覽器可以獲取到新鮮的資源?

          因此,使用 Cache-Control: no-cache 時,客戶端每次對服務(wù)器進行新鮮度校驗。

          PS:no-cache 與 no-store 的區(qū)別是什么?

          即使每次校驗新鮮度,也不需要每次都從服務(wù)器下載資源: 如果瀏覽器/CDN上緩存經(jīng)校驗沒有過期。這被稱為協(xié)商緩存,此時 http 狀態(tài)碼返回 304,指 Not Modified,即沒有變更。

          幸運的是,關(guān)于協(xié)商緩存,你無需管理,也無需配置, nginx 或者一些 OSS 都會自動配置協(xié)商緩存。

          而對于協(xié)商緩存,也有它們自己的算法,協(xié)商緩存的背后基于響應(yīng)頭 Last-Modified/ETag。瀏覽器每次請求資源時,會攜帶上次服務(wù)器響應(yīng)的 ETag/Last-Modified 作為標志,與服務(wù)端此時的 ETag/Last-Modified 作比較,來判斷內(nèi)容更改。

          http 響應(yīng)頭中的 ETag 值是如何生成的?

          而在操作系統(tǒng)底層,Last-Modified 往往通過文件系統(tǒng)(file system)中的 mtime 屬性生成。而 ETag 提供比 Last-Modified 更精細的檢驗粒度,由文件內(nèi)容的 hash 或者 mtime/size 生成。當然,這是后話。

          一定要為你的資源添加 Cache-Control 響應(yīng)頭

          我會經(jīng)常接觸到一些網(wǎng)站,他們的資源文件并沒有 Cache-Control 這個響應(yīng)頭。究其原因,在于緩存策略配置這個工作的職責不清,有時候它需要協(xié)調(diào)前端和運維。

          那如果不添加 Cache-Control 這個響應(yīng)頭會怎么樣?

          是不是每次都會自動去服務(wù)器校驗新鮮度,很可惜,不是。此時會對資源進行強制緩存,而對不帶有指紋信息的資源很有可能獲取到過期資源。 如果過期資源存在于瀏覽器上,還可以通過強制刷新瀏覽器來獲取最新資源。但是如果過期資源存在于 CDN 的邊緣節(jié)點上,CDN 的刷新就會復(fù)雜很多,而且有可能需要多人協(xié)作解決。

          那默認的強制緩存時間是多少

          首先要明確兩個響應(yīng)頭代表的含義:

          1. Date: 指源服務(wù)器響應(yīng)報文生成的時間,差不多與發(fā)請求的時間等價
          2. Last-Modified: 指靜態(tài)資源上次修改的時間,取決于 mtime

          LM factor 算法認為當請求服務(wù)器時,如果沒有設(shè)置 Cache-Control,如果距離上次的 Last-Modified 越遠,則生成的強制緩存時間越長。

          用公式表示如下,其中 factor 介于 0 與 1 之間:

          MaxAge = (Date - LastModified) * factor
          33a0fd498d00bb4514eb73c82afe2bc4.webpLM factor

          Bundle Splitting:盡量減少資源變更

          得益于單頁應(yīng)用與前端工程化的發(fā)展,經(jīng)過打包后,基本上所有資源都是帶有指紋信息的,這意味著所有的資源都是能夠設(shè)置永久緩存。打包策略如下圖所示:

          343bf20767b4a96edb03c3fbd7dc4a48.webp緩存控制策略

          但僅僅如此了嗎?

          如果你所有的 js 資源都打包成一個文件,它確實有永久緩存的優(yōu)勢。但是當有一行文件進行修改時,這一個大包的指紋信息發(fā)生改變,永久緩存失效。

          所以我們現(xiàn)在需要做到的是:當修改文件后,造成最小范圍的緩存失效。webpack 等打包工具雖然在 optimization 上內(nèi)置了很多性能優(yōu)化,但它不會幫你做這件事,這件事情需要自己動手。

          ef3589e45545f5eadb7d2a6e82b2e2d9.webp緩存控制策略

          此時我們可以對資源進行分層次緩存的打包方案,這是一個建議方案:

          1. webpack-runtime: 應(yīng)用中的 webpack 的版本比較穩(wěn)定,分離出來,保證長久的永久緩存
          2. react/react-dom: react 的版本更新頻次也較低
          3. vendor: 常用的第三方模塊打包在一起,如 lodashclassnames 基本上每個頁面都會引用到,但是它們的更新頻率會更高一些。另外對低頻次使用的第三方模塊不要打進來
          4. pageA: A 頁面,當 A 頁面的組件發(fā)生變更后,它的緩存將會失效
          5. pageB: B 頁面
          6. echarts: 不常用且過大的第三方模塊單獨打包
          7. mathjax: 不常用且過大的第三方模塊單獨打包
          8. jspdf: 不常用且過大的第三方模塊單獨打包

          隨著 http2 的發(fā)展,特別是多路復(fù)用,初始頁面的靜態(tài)資源不受資源數(shù)量的影響。因此為了更好的緩存效果以及按需加載,也有很多方案建議把所有的第三方模塊進行單模塊打包。

          小結(jié)

          ef3589e45545f5eadb7d2a6e82b2e2d9.webp緩存控制策略

          本篇文章地址在 前端工程化系列,歡迎訂閱。

          1. 前端高級進階:javascript 代碼是如何被壓縮的
          2. 前端高級進階:如何更好地優(yōu)化打包資源



          推薦閱讀




          我的公眾號能帶來什么價值?(文末有送書規(guī)則,一定要看)

          每個前端工程師都應(yīng)該了解的圖片知識(長文建議收藏)

          為什么現(xiàn)在面試總是面試造火箭?

          瀏覽 41
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美久久久久久久 | 人人操人人摸人人射 | 国产午夜在线 | 欧美成人在线观看网站 | 色婷婷免费在线 |