Manifest 是 H5提供的一種應用快取機制, 基於它web應用可以實現離線訪問(offline cache). 為此, 瀏覽器還提供了應用快取的api--applicationCache. 雖然manifest的技術已被web標準廢棄, 但這不影響我們嘗試去了解它. 也正是因為manifest的應用快取機制如此誘人, 餓了麼 和 office 365郵箱都還在使用著它!
通讀本文, 你將瞭解到如下內容:
- 描述
- 支援性
- 如何開啟應用快取
- manifest快取清單
- manifest快取狀態
- applicationCache
- manifest快取獨立性
- manifest快取規則
- webview的快取現象
- 最佳實踐
- 具體落地步驟
- 如何更新快取
- 其他
描述
對manifest熟悉的同學可以跳過此節.
鑑於manifest應用快取的技術, 我們可以做到:
- 離線訪問: 即使伺服器掛了, 或者沒有網路, 使用者依然可以正常瀏覽網頁內容.
- 訪問更快: 資料存在於本地, 省去了瀏覽器發起http請求的時間, 因此訪問更快, 移動端效果更為明顯.
- 降低負載: 瀏覽器只在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
, NETWORK
和 FALLBACK
. 如下, 先看一個栗子?:
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快取獨立性
- manifest的快取和瀏覽器預設的快取是兩套機制, 相互獨立, 並且不受瀏覽器快取大小限制(Chrome下測試結果).
- 各個manifest檔案的快取相互獨立, 各自在獨立的區域進行快取. 即使是快取同一個檔案, 也可能由於快取的版本不一致, 而造成各個頁面資源不一致.
manifest快取規則
- 遵循全量快取的規律. 即: manifest檔案改動後, 將重新快取一遍所有的檔案(包括html本身和動態新增的需要快取的檔案,即使快取列表中沒有該html). 第一次快取過程中如果出現快取失敗的檔案, 那麼, 第二訪問, 又將重新快取一遍所有的檔案. 以此類推.
- manifest檔案本身不能寫進快取清單, 否則連同html和資源在其快取失效之前, 將永遠不能獲得更新.
- 即使manifest檔案丟失, 快取依然有效. 不過從此以後, 引入該manifest的html, 將永遠不能獲得更新.
webview的快取現象
通常, webview的快取有如下三種現象:
- 普通網頁(無manifest檔案), 不受manifest快取影響, 快取只走 http cache.
- 包含manifest檔案的網頁, 快取檔案只受manifest快取影響(只有manifest檔案改變時才會更新快取資源), 快取資源完全與 http cache 無關, 但是
NETWORK
段落後需要訪問網路的檔案, 將繼續走 http cache. - webview直接載入manifest快取過的檔案時, 優先載入第一個manifest快取的該檔案, 如果沒有找到manifest快取, 那麼它將自動尋找 http cache 或者 線上載入.
最佳實踐
- 通常只使用一個manifest檔案, 並保證快取的檔案儘可能的少, 以減小manifest每次更新清單中檔案所耗費的時間和流量.
- 如果一定要使用兩個及以上manifest檔案, 快取檔案請儘量不要相同.
- 如果以上兩條都不能保證, 那麼, 請保證儘可能在manifest快取的狀態更新時, 主動去重新整理網頁.(此時並不能保證不同網頁之間同一個快取檔案版本一致)
具體落地步驟
如果快取的檔案需要加引數執行, 建議將引數內容加到hash中, 如:cached-page.html#parameterName=value
manifest 的引入可以使用絕對路徑或者相對路徑, 如果你使用的是絕對路徑, 那麼你的manifest檔案必須和你的站點處於同一個域名下.
manifest檔案你可以儲存為任意的副檔名, 但是響應頭中以下欄位須取以下定值, 以保證manifest檔案正確被解析, 並且它沒有http快取.
Content-Type: text/cache-manifest Cache-Control: max-age=0 Expires: [CURRENT TIME]複製程式碼
如何更新快取
- 更新manifest檔案後, webview將自動更新快取.
- js更新快取(手動觸發manifest更新): window.applicationCache.update();
其他
chrome瀏覽器下通過訪問 chrome://appcache-internals/ 可以檢視快取在本地的資原始檔.
另外, 除了本文參考的一篇 MDN 的文章以及 HTML5 Rocks的 Beginner's Guide to Using the Application Cache 一文, 還有如下三個連結可供您比較閱讀, 謝謝.
- Cache manifest in HTML5 on Wikipedia
- Offline Web Applications W3C Working Group Note
- Offline Web applications at WHATWG
本問就討論這麼多內容,大家有什麼問題或好的想法歡迎在下方參與留言和評論.
本文作者: louis
本文連結: louiszhai.github.io/2016/11/25/…
參考文章