html5離線存儲(chǔ)入門
Category:
(X)HTML&CSS,
JavaScript,
前端技術(shù) Tags:
api,
html5,
JavaScript,
離線存儲(chǔ)88 Comments所有的瀏覽器都有自己的緩存機(jī)制,但那些機(jī)制并不可靠而且難以控制,在你做web開發(fā)的時(shí)候可能經(jīng)常因?yàn)闉g覽器緩存帶來的問題而煩惱不已。html5通過
ApplicationCache接口解決了一些問題,并且使離線存儲(chǔ)成為可能,離線存儲(chǔ)使得你的web應(yīng)用可以在用戶離線的狀況下進(jìn)行訪問。這個(gè)技術(shù)顯然至少有三個(gè)好處:
最直接的好處就是用戶可以離線訪問你的web應(yīng)用
因?yàn)槲募痪彺嬖诒镜厥沟脀eb頁面加載速度提升許多
離線應(yīng)用只加載被修改過的資源,因此大大降低了用戶請(qǐng)求對(duì)服務(wù)器造成的負(fù)載壓力
如何實(shí)現(xiàn)離線文件存儲(chǔ)?
你的服務(wù)器得先支持html5!是的,這句話看上去像是以前在css森林群里大家說的“我的服務(wù)器不支持div+css”一樣的玩笑話。但我很嚴(yán)肅的告訴你,要實(shí)現(xiàn)離線存儲(chǔ)的應(yīng)用,你確實(shí)需要服務(wù)器的支持!容我細(xì)細(xì)道來,先來看看html5的離線文件存儲(chǔ)應(yīng)用對(duì)你的代碼有什么要求,你需要在頁面的html標(biāo)簽中通過manifest屬性引用一個(gè)manifest文件來使得你的應(yīng)用可緩存。簡單地說,manifest文件是一個(gè)文本文件,它羅列了離線訪問應(yīng)用時(shí)所需緩存的文件清單(注意:引用該manifest文件的頁面,不管你有沒有羅列到清單中,都會(huì)被緩存),但不只是這樣。代碼像下面這樣:
XHTML
1
2
3
<html manifest="test.manifest">
...
</html>
當(dāng)然,這個(gè)manifest的文件路徑用絕對(duì)路徑和相對(duì)路徑都可以,甚至可以引用其他服務(wù)器上的manifest文件。該文件所對(duì)應(yīng)的mime-type應(yīng)該是text/cache-manifest的,所以你需要配置服務(wù)器來發(fā)送對(duì)應(yīng)的MIME類型信息,服務(wù)器配置不在討論范圍內(nèi),請(qǐng)自行去了解吧。接下來要看的是manifest文件的結(jié)構(gòu),它的結(jié)構(gòu)很簡單,我們來看下面的例子:
1
2
3
4
5
CACHE MANIFEST
index.html
style.css
images/logo.png
scripts/mootools.js
這是最簡單的一個(gè)manifest文件的樣子,正如前面所提到的,文件羅列了需要被緩存的文件清單,第一行中的CACHE MANIFEST 是必須的,每個(gè)站點(diǎn)有5MB的空間來存儲(chǔ)這些數(shù)據(jù),如果manifest文件或文件里所列的文件無法加載,整個(gè)緩存更新過程將無法進(jìn)行,瀏覽器會(huì)使用最后一次成功的緩存。前面說過manifest文件不只是羅列要緩存的文件,那么它還有其他什么作用呢?讓我們來看個(gè)稍微復(fù)雜點(diǎn)的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
CACHE MANIFEST
# wanz app v1
# 指明緩存入口
CACHE:
index.html
style.css
images/logo.png
scripts/main.js
# 以下資源必須在線訪問
NETWORK:
login.php
# 如果index.php無法訪問則用404.html代替
FALLBACK:
/index.php /404.html
有經(jīng)驗(yàn)的同學(xué)一定可以看出來#是用來注釋一行的,但它還有一個(gè)小作用。web應(yīng)用的緩存只有在manifest文件被修改的情況下才會(huì)被更新,所以如果你只是修改了被緩存的文件,那么用戶本地的緩存還是不會(huì)被更新的,但是你可以通過修改manifest文件來告訴瀏覽器需要更新緩存了。利用這點(diǎn),你可以像上面的例子中那樣,寫一句這樣的注釋一個(gè)文件版本:
# wanz app v1
這樣寫有三個(gè)好處:
你可以很明確的了解離線web應(yīng)用的版本
通過簡單的修改這個(gè)版本號(hào)就可以輕易的通知瀏覽器更新
你可以配合JavaScript程序來完成緩存更新
正如你看到的,manifest文件有三個(gè)節(jié)點(diǎn),它們各自的含義如下:
CACHE:
這個(gè)是manifest文件的默認(rèn)入口,在此入口之后羅列的文件 (或直接寫在CACHE MANIFEST后的文件)在它們下載到本地后會(huì)被緩存起來
NETWORK:
可選的,在此節(jié)后面所羅列的文件是需要訪問網(wǎng)絡(luò)的,即使用戶離線訪問了也會(huì)直接跳過緩存而訪問服務(wù)器
FALLBACK:
可選的,用來指定資源無法訪問時(shí)的回調(diào)頁面。每一行包括兩個(gè)URI,第一個(gè)是資源文件URI,第二個(gè)是回調(diào)頁面URI。
備注:以上描述的這些節(jié)是沒有先后順序的,而且在同一個(gè)manifest中可以多次出現(xiàn)
到目前為止,你應(yīng)該了解如何來實(shí)現(xiàn)離線文件的存儲(chǔ)了,只需要三個(gè)步驟:1,配置服務(wù)器manifest文件的MIME類型;2,編寫manifest文件;3,在頁面的html標(biāo)簽的manifest屬性中引用寫好的manifest文件。
如何更新離線存儲(chǔ)?
你做到了,即使拔掉網(wǎng)線你也可以訪問你制作的頁面。于是你開始興致勃勃的豐富你的頁面,修改JavaScript代碼和css來實(shí)現(xiàn)更炫的頁面效果,然后將它們上傳到服務(wù)器,結(jié)果你會(huì)發(fā)現(xiàn):即使你刷新頁面刷到爆,清除n次歷史訪問記錄都無法看到你要的新的頁面效果。那是因?yàn)槟愀具€沒有更新html5的離線存儲(chǔ)文件?,F(xiàn)在的問題是如何更新html5離線緩存?下面的三種情況可以做到:
用戶清除了離線存儲(chǔ)的數(shù)據(jù),這個(gè)不一定就是清理瀏覽器歷史記錄就可以做到的,因?yàn)椴煌瑸g覽器管理離線存儲(chǔ)的方式不同。比如Firefox的離線存儲(chǔ)數(shù)據(jù)要到“選項(xiàng)”=>“高級(jí)”=>“網(wǎng)絡(luò)”=>“脫機(jī)存儲(chǔ)”里才可以清除。
manifest文件被修改,上面說的,你修改了manifest文件里所羅列的文件也不會(huì)更新緩存,而是要替換manifest文件
使用JavaScript api編寫更新程序
前面兩種方式很簡單,自己折騰吧。我們來看第三種,首先你需要對(duì)相關(guān)的api有所了解,詳細(xì)的前往查看:
http://www.whatwg.org/specs/web-apps/current-work/#applicationcache先簡單介紹下ApplicationCache和它的幾個(gè)重點(diǎn)屬性及方法:
cache = window . applicationCache
返回應(yīng)用于當(dāng)前window對(duì)象文檔的ApplicationCache對(duì)象
cache = self . applicationCache
返回應(yīng)用于當(dāng)前shared worker的ApplicationCache對(duì)象 [
shared worker]
cache . status
返回當(dāng)前應(yīng)用的緩存狀態(tài),status有五種無符號(hào)短整型值的狀態(tài):
UNCACHED = 0;
IDLE = 1;
CHECKING = 2;
DOWNLOADING = 3;
UPDATEREADY = 4;
OBSOLETE = 5;
cache . update()
調(diào)用當(dāng)前應(yīng)用資源下載過程
cache . swapCache()
更新到最新的緩存,這個(gè)不會(huì)使得之前加載的資源突然被重新加載。圖片不會(huì)重新加載,樣式和腳本也不會(huì)重新渲染或解析,唯一的變化是在此之后發(fā)出請(qǐng)求頁面的資源是最新的
applicationCache對(duì)象和緩存宿主的關(guān)系是一一對(duì)應(yīng),window對(duì)象的applicationCache屬性會(huì)返回關(guān)聯(lián)window對(duì)象的活動(dòng)文檔的applicationCache對(duì)象。在獲取status屬性時(shí),它返回當(dāng)前applicationCache的狀態(tài),它的值有以下幾種狀態(tài):
UNCACHED (數(shù)值 0)
此時(shí),ApplicationCache對(duì)象的緩存宿主與應(yīng)用緩存無關(guān)聯(lián)
IDLE (數(shù)值 1)
應(yīng)用緩存已經(jīng)是最新的,并且沒有標(biāo)記為obsolete
CHECKING (數(shù)值 2)
ApplicationCache對(duì)象的緩存宿主已經(jīng)和一個(gè)應(yīng)用緩存關(guān)聯(lián),并且該緩存的更新狀態(tài)是checking
DOWNLOADING (數(shù)值 3)
ApplicationCache對(duì)象的緩存宿主已經(jīng)和一個(gè)應(yīng)用緩存關(guān)聯(lián),并且該緩存的更新狀態(tài)是downloading
UPDATEREADY (數(shù)值 4)
ApplicationCache對(duì)象的緩存宿主已經(jīng)和一個(gè)應(yīng)用緩存關(guān)聯(lián),并且該緩存的更新狀態(tài)是idle,并且沒有標(biāo)記為obsolete,但是緩存不是最新的
OBSOLETE (數(shù)值 5)
ApplicationCache對(duì)象的緩存宿主已經(jīng)和一個(gè)應(yīng)用緩存關(guān)聯(lián),并且該緩存的更新狀態(tài)是obsolete
如果update方法被調(diào)用了,瀏覽器user agent就必須在后臺(tái)調(diào)用應(yīng)用緩存下載過程;如果swapCache方法被調(diào)用了,瀏覽器user agent會(huì)執(zhí)行以下步驟:
檢查ApplicationCache的緩存宿主是否與應(yīng)用緩存關(guān)聯(lián)
讓cache成為ApplicationCache對(duì)象的緩存宿主關(guān)聯(lián)的應(yīng)用緩存
如果cache的應(yīng)用緩存組被標(biāo)記為obsolete,那么就取消cache與ApplicationCache對(duì)象的緩存宿主的關(guān)聯(lián)并取消這些步驟,此時(shí)所有資源都會(huì)從網(wǎng)絡(luò)中下載而不是從緩存中
檢查在同一個(gè)緩存組中是否存在完成標(biāo)志為“完成”的應(yīng)用緩存,并且版本比cache更新
讓完成標(biāo)志為“完成”的新cache成為最新的應(yīng)用緩存
取消cache與ApplicationCache對(duì)象的緩存宿主的關(guān)聯(lián)并用新cache代替關(guān)聯(lián)
假設(shè)你已經(jīng)寫好的離線文件存儲(chǔ)的Demo頁面,通過下面的代碼可以來檢查,當(dāng)前頁面緩存的狀態(tài):
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var appCache = window.applicationCache;
switch (appCache.status) {
case appCache.UNCACHED: // UNCACHED == 0
alert( 'UNCACHED');
break;
case appCache.IDLE: // IDLE == 1
alert( 'IDLE');
break;
case appCache.CHECKING: // CHECKING == 2
alert ('CHECKING');
break;
case appCache.DOWNLOADING: // DOWNLOADING == 3
alert( 'DOWNLOADING');
break;
case appCache.UPDATEREADY: // UPDATEREADY == 5
alert ('UPDATEREADY');
break;
case appCache.OBSOLETE: // OBSOLETE == 5
alert ('OBSOLETE');
break;
default:
alert ('UKNOWN CACHE STATUS');
break;
};
一個(gè)更新的實(shí)現(xiàn)過程大概是這樣的:首先調(diào)用applicationCache.update()使得瀏覽器開始嘗試更新,前提是你的manifest文件是更新過的(比如前面所說的,修改了版本號(hào));在applicationCache.status為UPDATEREADY 狀態(tài)時(shí)就可以調(diào)用applicationCache.swapCache()來將舊的緩存更新為新的。
JavaScript
1
2
3
4
5
6
7
var appCache = window.applicationCache;
appCache.update(); // 開始更新
if (appCache.status == window.applicationCache.UPDATEREADY) {
appCache.swapCache(); // 得到最新版本緩存列表,并且成功下載資源,更新緩存到最新
}
沒錯(cuò),更新過程也可以很簡單,但是一個(gè)好的應(yīng)用少不了容錯(cuò)處理,就如Ajax技術(shù)一樣,你需要對(duì)更新過程進(jìn)行監(jiān)控,處理各種異?;蛱崾镜却隣顟B(tài)來使你的應(yīng)用更強(qiáng)壯,用戶體驗(yàn)更好,因此你需要了解applicationCache的更新過程所觸發(fā)的事件,它們是:onchecking,onerror,onnoupdate,ondownloading,onprogress,onupdateready,oncached和onobsolete。監(jiān)聽事件的代碼你應(yīng)該也都輕車熟路了,假設(shè)你要對(duì)更新錯(cuò)誤進(jìn)行處理,你可以這樣寫:
JavaScript
1
2
3
4
5
6
7
8
9
var appCache = window.applicationCache;
// 請(qǐng)求manifest文件時(shí)返回404或410,下載失敗
// 或manifest文件在下載過程中源文件被修改會(huì)觸發(fā)error事件
appCache.addEventListener('error', handleCacheError, false);
function handleCacheError(e) {
alert('Error: Cache failed to update!');
};
不管是manifest文件還是它所羅列的資源文件下載失敗,整個(gè)更新過程就終止了,瀏覽器會(huì)使用上一個(gè)最新的緩存。更多關(guān)于事件的內(nèi)容請(qǐng)前往:
http://www.whatwg.org/specs/web-apps/current-work/#event-handlers經(jīng)過一段時(shí)間的測試,我建議大家在chrome下做實(shí)驗(yàn),因?yàn)橛胒irefox的實(shí)現(xiàn)就像屎,有這個(gè)功能卻很臭!,最后獻(xiàn)上離線應(yīng)用的demo一枚:
丸子的友鄰類似文章
2010年08月25日
HTML5本地存儲(chǔ) (10)
2010年04月13日
canvas JavaScript API學(xué)習(xí)(一) (3)
2010年04月17日
canvas JavaScript API學(xué)習(xí)(二) (6)
2010年04月19日
canvas JavaScript API學(xué)習(xí)(三) (21)
2010年04月22日
canvas JavaScript API學(xué)習(xí)(四) (1)