聊一聊 H5 應用快取 - Manifest

路易斯發表於2017-04-13

Manifest 是 H5提供的一種應用快取機制, 基於它web應用可以實現離線訪問(offline cache). 為此, 瀏覽器還提供了應用快取的api--applicationCache. 雖然manifest的技術已被web標準廢棄, 但這不影響我們嘗試去了解它. 也正是因為manifest的應用快取機制如此誘人, 餓了麼 和 office 365郵箱都還在使用著它!

通讀本文, 你將瞭解到如下內容:


  1. 描述
  2. 支援性
  3. 如何開啟應用快取
  4. manifest快取清單
  5. manifest快取狀態
  6. applicationCache
  7. manifest快取獨立性
  8. manifest快取規則
  9. webview的快取現象
  10. 最佳實踐
  11. 具體落地步驟
  12. 如何更新快取
  13. 其他

描述

對manifest熟悉的同學可以跳過此節.

鑑於manifest應用快取的技術, 我們可以做到:

  • 離線訪問: 即使伺服器掛了, 或者沒有網路, 使用者依然可以正常瀏覽網頁內容.
  • 訪問更快: 資料存在於本地, 省去了瀏覽器發起http請求的時間, 因此訪問更快, 移動端效果更為明顯.
  • 降低負載: 瀏覽器只在manifest檔案改動時才去伺服器下載需要快取的資源, 大大降低了伺服器負載.

manifest快取的過程如下(來自網路):

聊一聊 H5 應用快取 - Manifest
manifest

支援性

主流瀏覽器都支援manifest應用快取技術. 如下表格:

IE Edge Firefox Chrome Safari Opera ios Android
10+ 12+ 3.5+ 4+ 4+ 11.5+ 7.1+ 2.3+

H5標準中, Offline Web applications 部分有如下描述:

This feature is in the process of being removed from the Web platform. (This is a long process that takes many years.) Using any of the offline Web application features at this time is highly discouraged. Use service workers instead. [SW]

因此後續我將在其他文章中繼續介紹 service workers, 本篇繼續關注manifest.

如何開啟應用快取

manifest使用快取清單進行管理, 快取清單需要與html標籤進行關聯. 如下:

<html manifest="test.appcache">
  ...
</html>複製程式碼

在html標籤中指定manifest檔案, 便表示該網頁使用manifest進行離線快取. 該網頁內需要快取的檔案列表需要在 test.appcache 文字檔案中指定.

manifest快取清單

就像寫作文一樣, manifest採用經典的三段式. 分別為: CACHE, NETWORKFALLBACK. 如下, 先看一個栗子?:

CACHE MANIFEST
# v1.0.0
content.css

NETWORK:
app.js

FALLBACK:
/other 404.html複製程式碼

其中第一行必須以 CACHE MANIFEST 開頭, 後可跟若干字元註釋, 註釋從#號開始. 跟在 CACHE MANIFEST 行後的檔案, 每行列出一個, 這些檔案是需要快取的檔案. 因此 content.css 會被快取, 不需要訪問網路.

第二段內容以 NETWORK: 開始, 跟在該行後的檔案表示需要訪問網路. 如: app.js 將直接從網路上下載, 並不走manifest cache, 如果除了第一段中快取的檔案以外, 其他檔案都從網路上獲取, 那麼此時可將 app.js 改為 * (萬用字元).

第三段內容以 FALLBACK: 開始, 跟在該行後的檔案表示會有一個替代方案. 如: 當訪問 /other 路徑時, 如果訪問失敗, 那麼將自動載入 404.html 作為替代.

manifest快取狀態

每個manifest快取都有一個狀態, 標示著快取的情況. 一份快取清單隻有一個快取狀態, 即使它被多個頁面引用. 以下是各個快取狀態:

  • UNCACHED(未快取): 表明應用快取物件還沒有初始化完成.
  • IDLE(空閒): 應用快取並未處於更新狀態.
  • CHECKING(檢查): 正在檢查是否存在更新.
  • DOWNLOADING(下載): 清單更新後, 重新下載全部資源到臨時快取中.
  • UPDATEREADY(更新就緒): 新版本的快取下載完成, 全部就緒, 隨即觸發事件 updateready.
  • OBSOLETE(廢棄): 應用快取已被廢棄.

上述快取狀態常量依次取值0, 1, 2, 3, 4, 5.

applicationCache

applicationCache是操作應用快取的瑞士軍刀, 也是唯一的一把刀.

首先我們來獲取該物件.

//webview下
var cache = window.applicationCache;
//shared worker中
var cache = self.applicationCache;複製程式碼

以下是其屬性和方法介紹(大神請繞過):

  • status: 返回當前頁面的應用快取的狀態, 通常開啟應用快取的頁面可能返回1, 其他頁面則返回0.

  • update(): 手動觸發應用快取的更新.

    (1) 若有更新, 則依次觸發①檢查事件(Checking event), ②下載事件(Downloading event), ③下載進度事件(Progress event), ④更新完成事件(UpdateReady event);

    (2) 若無更新, 則依次觸發①檢查事件(Checking event), ②無更新事件(NoUpdate event);

    (3) 在未開啟應用快取的頁面呼叫將丟擲Uncaught DOMException 錯誤.

    update() 方法通常在長時間不關閉的頁面使用, 比如說郵箱應用, 用於定期檢測可能的更新.

  • abort(): 取消應用快取的更新. 可用於節省有限的網路頻寬.

  • swapCache(): 如果存在一個更新版本的應用快取, 那麼它將切換過去, 否則將丟擲 Uncaught DOMException 錯誤. 通常, 我們會在updateready事件觸發之後手動呼叫swapCache()方法, swapCache的切換隻對後續載入的快取檔案有效, 已經載入成功的資源並不會重新載入.

那麼如何利用好上述api更新一個頁面的應用快取呢? 別急, Beginner's Guide to Using the Application Cache 一文中提供瞭如下的樣板方法:

// Check if a new cache is available on page load.
window.addEventListener('load', function(e) {
  window.applicationCache.addEventListener('updateready', function(e) {
    if (window.applicationCache.status == window.applicationCache.UPDATEREADY) {
      // Browser downloaded a new app cache.
      // Swap it in and reload the page to get the new hotness.
      window.applicationCache.swapCache();
      if (confirm('A new version of this site is available. Load it?')) {
        window.location.reload();
      }
    } else {
      // Manifest didn't changed. Nothing new to server.
    }
  }, false);
}, false);複製程式碼

manifest快取獨立性

  1. manifest的快取和瀏覽器預設的快取是兩套機制, 相互獨立, 並且不受瀏覽器快取大小限制(Chrome下測試結果).
  2. 各個manifest檔案的快取相互獨立, 各自在獨立的區域進行快取. 即使是快取同一個檔案, 也可能由於快取的版本不一致, 而造成各個頁面資源不一致.

manifest快取規則

  1. 遵循全量快取的規律. 即: manifest檔案改動後, 將重新快取一遍所有的檔案(包括html本身和動態新增的需要快取的檔案,即使快取列表中沒有該html). 第一次快取過程中如果出現快取失敗的檔案, 那麼, 第二訪問, 又將重新快取一遍所有的檔案. 以此類推.
  2. manifest檔案本身不能寫進快取清單, 否則連同html和資源在其快取失效之前, 將永遠不能獲得更新.
  3. 即使manifest檔案丟失, 快取依然有效. 不過從此以後, 引入該manifest的html, 將永遠不能獲得更新.

webview的快取現象

通常, webview的快取有如下三種現象:

  1. 普通網頁(無manifest檔案), 不受manifest快取影響, 快取只走 http cache.
  2. 包含manifest檔案的網頁, 快取檔案只受manifest快取影響(只有manifest檔案改變時才會更新快取資源), 快取資源完全與 http cache 無關, 但是 NETWORK 段落後需要訪問網路的檔案, 將繼續走 http cache.
  3. webview直接載入manifest快取過的檔案時, 優先載入第一個manifest快取的該檔案, 如果沒有找到manifest快取, 那麼它將自動尋找 http cache 或者 線上載入.

最佳實踐

  1. 通常只使用一個manifest檔案, 並保證快取的檔案儘可能的少, 以減小manifest每次更新清單中檔案所耗費的時間和流量.
  2. 如果一定要使用兩個及以上manifest檔案, 快取檔案請儘量不要相同.
  3. 如果以上兩條都不能保證, 那麼, 請保證儘可能在manifest快取的狀態更新時, 主動去重新整理網頁.(此時並不能保證不同網頁之間同一個快取檔案版本一致)

具體落地步驟

  1. 如果快取的檔案需要加引數執行, 建議將引數內容加到hash中, 如:cached-page.html#parameterName=value

  2. manifest 的引入可以使用絕對路徑或者相對路徑, 如果你使用的是絕對路徑, 那麼你的manifest檔案必須和你的站點處於同一個域名下.

  3. manifest檔案你可以儲存為任意的副檔名, 但是響應頭中以下欄位須取以下定值, 以保證manifest檔案正確被解析, 並且它沒有http快取.

    Content-Type: text/cache-manifest
    Cache-Control: max-age=0
    Expires: [CURRENT TIME]複製程式碼

如何更新快取

  1. 更新manifest檔案後, webview將自動更新快取.
  2. js更新快取(手動觸發manifest更新): window.applicationCache.update();

其他

chrome瀏覽器下通過訪問 chrome://appcache-internals/ 可以檢視快取在本地的資原始檔.

另外, 除了本文參考的一篇 MDN 的文章以及 HTML5 Rocks的 Beginner's Guide to Using the Application Cache 一文, 還有如下三個連結可供您比較閱讀, 謝謝.


本問就討論這麼多內容,大家有什麼問題或好的想法歡迎在下方參與留言和評論.

本文作者: louis

本文連結: louiszhai.github.io/2016/11/25/…

參考文章

相關文章