緩存控制中的 stale-while-revalidate

stale-while-revalidateHTTP RFC 5861 中描述的一種 Cache-Control 擴展,屬於對緩存到期的控制。html

緩存控制

不少人都瞭解瀏覽器的緩存機制,這裏簡單溫習一下。爲了提升響應速度,瀏覽器會幫咱們把一些請求的響應緩存下來,在下次請求相同的資源時,直接返回緩存的結果。但業務中有些資源時不該該緩存的,應該老是請求最新的結果,瀏覽器怎麼判斷哪些資源能夠緩存,緩存多久這些信息呢?HTTP 緩存文檔中容許服務端設置一些響應頭 (如 Cache-control) 來告訴瀏覽器如何緩存這個響應。前端

Cache-Control: max-age=600
複製代碼

max-age 就是 Cache-control 包含的一個指令,用於設置緩存存儲的最大週期,超過這個時間緩存被認爲過時(單位秒)。好比上面的例子,在 600 秒內,再次請求這個資源,瀏覽器就會返回緩存的響應,超過這個時間後,請求這個資源,瀏覽器就會請求新的結果,應用就須要等待這個請求。web

含義

那咱們回到 stale-while-revalidate=<seconds>。它代表客戶端願意接受陳舊 (stale) 的響應,同時在後臺異步檢查新的響應 (revalidate)。秒值指示客戶願意接受陳舊響應的時間長度。瀏覽器

怎麼樣的響應算是陳舊的響應?緩存

stale-while-revalidate 指令應當與 max-age 配合使用,超過 max-age 指定的時間的響應就是陳舊的響應。與之相對的,沒有超過期間的就是新鮮的 (fresh) 響應。若是一個緩存的響應沒有超過 max-age 指定的時間(還是新鮮的),按照上面講的緩存機制,此時請求這個資源,瀏覽器會直接返回緩存的結果。若是緩存的結果已經陳舊了呢?按照前面講的緩存機制,瀏覽器應該去請求新的響應了,可是若是存在 stale-while-revalidate 指令就不同了,瀏覽器會檢查這個陳舊的響應是否超過了 stale-while-revalidate 規定的時間窗口。若是沒有超過,那麼瀏覽器仍然會直接返回緩存的結果,同時在後臺請求新的結果用來更新緩存。bash

有點繞…異步

咱們看 RFC 5861 給出的示例用法。優化

用法

Cache-Control: max-age=600, stale-while-revalidate=30
複製代碼

這個響應頭規定了緩存的週期爲 600 秒,可接受 30 秒內的陳舊響應。若是在 600 秒以內請求這個資源,瀏覽器就會直接返回緩存的響應。若是在 600 秒以後請求,瀏覽器會檢查是否已經超過可接受的陳舊時間,也就是總共是否超過了 630 秒。若是沒有超過的話,仍然返回緩存的響應,同時在後臺請求新的響應。若是超過了 630 秒,就直接請求新的響應,應用將等待這個請求。google

這和直接設置 max-age=630 有什麼不同?spa

咱們設想這樣一個步驟,比較兩種方式的異同。

設置 max-age=630

  1. 初次請求,應用等待請求,獲得新鮮的響應,存入緩存
  2. 在 600 秒內再次請求,不用等,獲得緩存響應
  3. 在 610 秒時再次請求,不用等,獲得緩存響應
  4. 在 640 秒時再次請求,應用等待請求,獲得新鮮的響應,存入緩存

設置 max-age=600, stale-while-revalidate=30

  1. 初次請求,應用等待請求,獲得新鮮響應,存入緩存
  2. 在 600 秒內再次請求,不用等,獲得緩存響應
  3. 在 610 秒時再次請求,不用等,獲得緩存響應,同時後臺請求了新的響應,存入緩存
  4. 在 640 秒時再次請求,不用等,獲得 610 秒時刷新的緩存響應

能夠看到咱們在 640 秒時的這個請求,即不用等,也保證了新鮮度。實際上,咱們在超過 max-age 的週期以後,在 stale-while-revalidate 指定的時間窗口以內發出的請求,都會獲得這個做用。

若是沒有剛好在那 30 秒內請求不仍是沒用麼

說對了。600 和 30 這兩個數值的搭配可能並不能讓你想到實際使用場景,咱們來舉一個實例。

實例

假設我有一個 HTTP API,它返回如今是當前小時的第幾分鐘。它具備以下緩存控制響應頭:

Cache-Control: max-age=1, stale-while-revalidate=59
複製代碼

若是在 1 秒鐘內從新請求,那麼分鐘數和原來是同樣的,以前緩存的結果徹底是新鮮的;若是在 1-60 秒內請求,須要請求一個新的結果了,但原來的結果也不是不能用;若是在超過 60 秒後請求,則必定須要新的結果。

從這個例子能夠看出,stale-while-revalidate 比較適用的場景是,咱們查詢的信息須要被刷新,但必定程度的陳舊是能夠接受的。一般來說,這種場景對應的業務是,咱們請求的會資源在已知的或者可預見的週期內定時更新,同時咱們會屢次請求這個資源。在這樣的場景下,stale-while-revalidate 能夠在提供新鮮度有保證的響應結果的同時,減小重複請求的等待時間。

等等,這聽起來有點像…

咱們在開發應用時,爲了減小請求的等待時間,減小空白頁的出現,有時會在請求完成後,按照請求的 URL 等標識,將請求結果存儲在 Redux/Vuex 等介質中,在頁面上從 store 中讀取數據來顯示,而不是直接在 state 中維護和顯示請求結果。這樣一來,當須要從新請求相同的資源時,咱們能夠在界面上看到上次請求的結果,隨後看到新的結果,減小空白頁的出現。

若是你也有這樣的操做,或者想要有這樣的操做,不妨看看 zeit 的 swr 庫,它已經幫你作了。swrstale-while-revalidate 的縮寫,雖然得名於此,swr 只是借用了它的思想,實際實現與 stale-while-revalidate 指令並沒有關係。swr 在早讀課的另外一篇文章有介紹。這裏很少贅述。

瀏覽器兼容性

stale-while-revalidate 不是緩存標準文檔的一部分,而是擴展內容,屬於實驗性質。目前桌面瀏覽器只有 Chrome 7五、Firefox 6八、Edge 79 起對其有支持。

總結

緩存控制是應用優化中一個通用的、經常使用的方法,它不是單純的前端技術或知識,也並不是一晚上之間就能一把梭的方法。不少時候緩存控制應該結合實際業務需求,對各個資源有針對性地使用,以在信息的準確性和響應的時間上達到最佳的平衡。

最後分享一句格言,它是 Google Web 指南里的一個章節標題。

Never load the same resource twice.

參考連接

相關文章
相關標籤/搜索