前端性能優化(Application Cache篇)

正巧看到在送書,因而乎找了找本身博客上記錄過的一些東西來及其無恥的蹭書了~~~javascript

小廣告:更多內容能夠看個人博客css

以前在segmentfault上刷問題看到一個關於manifest的問題,很好奇就研究了一下application cache。Application Cache是HTML5的新特性,容許瀏覽器在本地存儲頁面所須要的資源,使得頁面離線也能夠訪問。以前研究的目的是爲了在博客中使用,將一些不須要改動的CSS、JavaScript、圖片文件離線緩存,這樣加載速度必然飛起,但願能用在博客上,可是失敗了,但仍是記錄一下學到的知識html

Application Cache的配置文件

首先須要在服務器上創建一個文件,裏面的內容肯定了哪些文件須要緩存,哪些文件不須要,若是資源沒法訪問會使用什麼頁面等java

這個文件通常爲.appcache類型,稱爲緩存清單(cache manifest)文件,一個完整的緩存清單文件以下:chrome

CACHE MANIFEST
# version xx.xx.xx
CACHE:
needBeCached.png
needBeCached2.js

NETWORK:
notNeedBeCached.html
notNeedBeCached2.css

FALLBACK:
/ 404.html

能夠看到,文件的頭部信息CACHE MANIFEST用來標註這個文件是緩存清單文件,其後通常狀況下(最好是)跟着一行標明版本的註釋,這行註釋很是重要,將在後面文件加載部分詳細介紹這行註釋的重要性segmentfault

CACHE部分

除了頭部信息,這個緩存清單文件分爲幾部分,第一部分爲CACHE部分:瀏覽器

CACHE:
needBeCached.png
needBeCached2.js

這一部分標註了哪些資源文件須要被緩存能夠列出多個緩存

若是有路徑,如須要緩存blog下的blog.css文件,能夠寫成blog/blog.css服務器

另外CACHE:能夠被省略,讓須要緩存的資源文件直接跟在註釋以後網絡

NETWORK部分

第二部分爲NETWORK部分:

NETWORK:
notNeedBeCached.html
notNeedBeCached2.css

這一部分定義了哪些文件不須要緩存,這些文件須要與服務器鏈接

與CACHE同樣,能夠定義多個資源,而若是直接輸入一個文件夾路徑,也是合法的,好比/blog這樣,blog文件夾下的全部文件都不會被緩存

可使用通配符來,如除了上面CACHE中定義的資源,其餘都必須與服務器鏈接:

NETWORK:
*

須要注意一點是,載有這個manifest文件的HTML文檔將必定會緩存,這個會在後面再次提到

FALLBACK部分

第三部分爲FALLBACK部分:

FALLBACK:
/ 404.html

這一部分指定了一個後備頁面,當資源沒法訪問時,瀏覽器會使用該頁面

一樣能夠定義多條記錄,每條記錄列出兩個URI,一個表示資源,一個表示後備頁面。須要注意的是兩個資源文件都須要使用相對路徑切與manifest文件同源

一樣可使用通配符

保存和引用manifest文件

manifest文件能夠保存在服務器上,保存爲.appcache後綴,但必須與應用自己同源。在HTML文檔中,能夠指定清單文件的相對路徑和絕對URL。須要注意的是,manifest文件的MIME類型必須是text/cache-manifest

須要在HTML文檔中引入manifest文件,可使用相似以下代碼:

<!doctype html>
<html manifest="manifest.appcache">
...
</html>

這樣,HTML文檔加載後,就會根據manifest.appcache的內容來緩存資源文件,在下次訪問相同頁面的時候,會直接使用緩存的資源文件來進行加速

緩存和加載機制

在第一次訪問時,瀏覽器加載完HTML文檔後,會查看其是否有引入manifest文件。若引入,則加載manifest文件,而後根據manifest的文件內容進行資源的緩存,並緩存當前文檔

以後訪問,瀏覽器首先會查看manifest文件是否被修改(不管是內容仍是註釋),若是被修改,將當作第一次訪問,從新根據manifest文件內容進行緩存

若是應用緩存存在,且manifest沒有被修改,瀏覽器直接從緩存中加載文檔(注意:加載文檔)和資源,不會訪問網絡(注意:不管聯網與否,都不會訪問網絡)

在緩存多個資源文件時,瀏覽器下載資源文件會先放在一個臨時的緩存中,若是有任何一個資源文件下載失敗,瀏覽器將中止其餘緩存資源的下載,並清除臨時緩存。若是全部資源文件都被成功下載,瀏覽器將會把這些資源文件以及引用manifest文件的HTML文檔移動到永久離線緩存中

滿滿的都是坑

一些小坑

  1. 須要注意的是manifest文件放在服務器上,MIME類型必須是text/cache-manifest,若是使用 Apache,須要修改.htaccess文件。IE下默認application/octet-stream,須要在服務器指定
  2. 每一個須要緩存的頁面的html都須要加入manifest屬性
  3. 不要將manifest文件自己加入緩存,若是加入,瀏覽器將不會檢測到服務器上manifest的更新,頁面版本將萬年不變
  4. 不要覺得一個資源文件加載失敗,其餘文件就會被緩存,緣由參見緩存和加載機制的最後一段

一些大坑

  1. 在manifest文件中定義的資源所有被成功加載後,這些資源文件連同引用manifest文件的HTML文檔一併被移動到永久離線緩存中。因此若是想只緩存js、css、圖片等文件,而不但願緩存HTML文檔以保持得到最新內容的狀況來講,這就是個大坑
  2. 根據Application Cache的加載機制,若是僅僅修改資源文件的內容(沒有修改資源文件的路徑或名稱),瀏覽器將直接從本地離線緩存中獲取資源文件。因此在每次修改資源文件的同時,須要修改manifest文件,以觸發資源文件的從新加載和緩存。這其中,最有效的方式是修改manifest文件內部的版本註釋(因此說那句註釋至關重要)
  3. 若是資源沒有被緩存,在而沒有設置NETWORK的狀況下,將會沒法加載(瀏覽器不會去網絡上進行加載),因此須要使用通配符來代表除了CACHE中肯定的資源之外,其餘資源都須要去網絡上加載

使用iframe來避開一號坑?

網上傳言避開一號坑的方法是使用iframe來指定須要緩存的資源,而避開HTML文檔的緩存。具體作法是在HTML中嵌入一個iframe,iframe中的頁面的HTML標籤包含manifest屬性引用manifest文件,裏面定義了須要緩存的文件。這樣就會只緩存iframe中的HTML文檔,而持續更新主頁面:

<!doctype html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>主頁面</title>
    <link rel="stylesheet" href="css/style.css">
    <script src="js/javascript.js"></script>
</head>
<body>
    <iframe src="cache.html"></iframe>
</body>
</html>

能夠看到,主頁面的html標籤中,並無引入manifest文件。只是在其中加載了一個iframe,而這個iframe所加載的頁面文檔以下:

<!DOCTYPE html>
<html manifest="manifest.appcache">
<head>
    <meta charset=utf-8 />
    <title>緩存頁面</title>
</head>
<body>
</body>
</html>

緩存頁面中引入了manifest文件,這樣瀏覽器就會緩存manifest文件中定義的資源列表,好比這裏manifest文件的內容以下:

CACHE MANIFEST
# VERSION 1.0

CACHE:
css/someStyle.css
js/someJavaScript.js

NETWORK:
*

在chrome中運行,能夠在命令行中看到以下效果:

Creating Application Cache with manifest http://localhost:8000/manifest.appcache
Application Cache Checking event
Application Cache Downloading event
Application Cache Progress event (0 of 2) http://localhost:8000/css/someStyle.css
Application Cache Progress event (1 of 2) http://localhost:8000/js/someJavaScript.js
Application Cache Progress event (2 of 2)
Application Cache Cached event

瀏覽器緩存了manifest文件中定義的資源文件,其實同時還緩存了iframe中的緩存頁面的文檔,但不會緩存主頁面,修改一下主頁面,並按F5刷新

Document was loaded from Application Cache with manifest http://localhost:8000/manifest.appcache
Application Cache Checking event
Application Cache NoUpdate event

能夠看到主頁面被更新了,可是someStyle.css和someJavaScript.js文件依舊從網絡上加載了,而沒有從cache中加載。打開chrome的chrome://appcache-internals/能夠看到,裏面cache.html、someStyle.css、someJavaScript.js確實被緩存了,去掉NETWORK段,結果也是同樣

Flags       URL                                         Size (headers and data)
Master,     http://localhost:8000/cache.html            388 B
Explicit,   http://localhost:8000/css/someStyle.css     228 B
Explicit,   http://localhost:8000/js/someJavaScript.js  244 B
Manifest,   http://localhost:8000/manifest.appcache     316 B

在firefox、opera上測試也是同樣,雖然被緩存了,但依舊會從網絡上加載,而iframe的解答方法也是2011~2012年左右提出的,後來就沒有相關文章了,估計已經完全失效了

總結

Application主要是爲了構建離線緩存,使得頁面在離線模式下也能瀏覽。這比較適合一些頁面上的應用以及靜態的不常常變動的頁面。其會緩存載體頁面也是因爲其機制。若是上面iframe機制實現有錯誤,或是有其餘方法只緩存資源不緩存HTML文檔,請聯繫我

參考資料

使用應用緩存

Application Cache 就是個坑

相關文章
相關標籤/搜索