第23 離線應(yīng)用與客戶端存儲(chǔ)
1. 離線檢測
(1)
navigator.onLine 屬性
,這個(gè)屬性值為true表示設(shè)備能上網(wǎng),值為false表示設(shè)備離線。
(2)兩個(gè)事件: online 和 offline。
當(dāng)網(wǎng)絡(luò)從離線變?yōu)樵诰€或者從在線變?yōu)殡x線時(shí),分別觸發(fā)這兩個(gè)事件。這兩個(gè)事 件在 window 對象上觸發(fā)映之。
2. 應(yīng)用緩存
(1) HTML5 的
應(yīng)用緩存(application cache)
,或者簡稱為 appcache,是專門為開發(fā)離線 Web 應(yīng)用而設(shè)計(jì) 的穴豫。Appcache 就是從瀏覽器的緩存中分出來的一塊緩存區(qū)皮钠。要想在這個(gè)緩存中保存數(shù)據(jù),可以使用一個(gè)描述文件(manifest file)
,列出要下載和緩存的資源晚岭。
(2) 要將描述文件與頁面關(guān)聯(lián)起來,可以在<html>中的 manifest 屬性中指定這個(gè)文件的路徑<htmlmanifest="/offline.manifest">
這個(gè)文件的 MIME 類型必須是 text/cache-manifest1迂烁。
(3)applicationCache 對象
,這個(gè)對象有一個(gè)status 屬性
,屬性的值是常量,表示應(yīng)用緩存的如下當(dāng)前狀態(tài)州袒。
- 0:無緩存,即沒有與頁面相關(guān)的應(yīng)用緩存揭绑。
- 1:閑置,即應(yīng)用緩存未得到更新。
- 2:檢查中,即正在下載描述文件并檢查更新稳析。
- 3:下載中,即應(yīng)用緩存正在下載描述文件中指定的資源洗做。
- 4:更新完成,即應(yīng)用緩存已經(jīng)更新了資源,而且所有資源都已下載完畢,可以通過 swapCache()來使用了。
- 5:廢棄,即應(yīng)用緩存的描述文件已經(jīng)不存在了,因此頁面無法再訪問應(yīng)用緩存彰居。
(4) 應(yīng)用緩存還有很多相關(guān)的事件,表示其狀態(tài)的改變诚纸。以下是這些事件。
- checking:在瀏覽器為應(yīng)用緩存查找更新時(shí)觸發(fā)陈惰。
- error:在檢查更新或下載資源期間發(fā)生錯(cuò)誤時(shí)觸發(fā)畦徘。
- noupdate:在檢查描述文件發(fā)現(xiàn)文件無變化時(shí)觸發(fā)。
- downloading:在開始下載應(yīng)用緩存資源時(shí)觸發(fā)抬闯。
- progress:在文件下載應(yīng)用緩存的過程中持續(xù)不斷地觸發(fā)井辆。
- updateready:在頁面新的應(yīng)用緩存下載完畢且可以通過 swapCache()使用時(shí)觸發(fā)。
- cached:在應(yīng)用緩存完整可用時(shí)觸發(fā)
(5)
update()方法
也可以 手工干預(yù),讓應(yīng)用緩存為檢查更新而觸發(fā)上述事件溶握。applicationCache.update();
(6) 如果觸發(fā)了updateready 事件
,則說明新版本的應(yīng)用緩存已經(jīng)可用,而此時(shí)你需 要調(diào)用swapCache()來啟用新應(yīng)用緩存
杯缺。
EventUtil.addHandler(applicationCache, "updateready", function(){
applicationCache.swapCache();
});
3. 數(shù)據(jù)存儲(chǔ)
(1) Cookie
HTTP Cookie
,通常直接叫做 cookie,最初是在客戶端用于存儲(chǔ)會(huì)話信息的。該標(biāo)準(zhǔn)要求服務(wù)器對任意 HTTP 請求發(fā)送Set-Cookie
HTTP 頭作為響應(yīng)的一部分,其中包含會(huì)話信息睡榆。- 瀏覽器會(huì)存儲(chǔ)這樣的會(huì)話信息,并在這之后,通過為每個(gè)請求添加
Cookie HTTP 頭
將信 息發(fā)送回服務(wù)器萍肆。
* 限制
cookie 在性質(zhì)上是綁定在
特定的域名下
的袍榆。當(dāng)設(shè)定了一個(gè) cookie 后,再給創(chuàng)建它的域名發(fā)送請求時(shí), 都會(huì)包含這個(gè) cookie。這個(gè)限制確保了儲(chǔ)存在 cookie 中的信息只能讓批準(zhǔn)的接受者訪問,而無法被其他 域訪問塘揣。
- 每個(gè)域的 cookie 總數(shù)是有限的,不過瀏覽器之間各有不同包雀。
- 瀏覽器中對于 cookie 的尺寸也有限制。大多數(shù)瀏覽器都有大約 4096B(加減 1)的長度限制亲铡。
*cookie 的構(gòu)成
cookie 由瀏覽器保存的以下幾塊信息構(gòu)成:
- 名稱(name):一個(gè)唯一確定 cookie 的名稱才写。cookie 名稱是不區(qū)分大小寫的,所以 myCookie 和 MyCookie 被認(rèn)為是同一個(gè) cookie。然而,實(shí)踐中最好將 cookie 名稱看作是區(qū)分大小寫的,因?yàn)槟承┓?wù)器會(huì)這樣處理 cookie奖蔓。cookie 的名稱必須是經(jīng)過 URL 編碼的赞草。
- 值:儲(chǔ)存在 cookie 中的字符串值。值必須被 URL 編碼锭硼。
- 域(domain):cookie 對于哪個(gè)域是有效的房资。所有向該域發(fā)送的請求中都會(huì)包含這個(gè) cookie 信息蜕劝。這個(gè)值
可以包含子域(subdomain,如 www.wrox.com),也可以不包含它(如.wrox.com,則對于 wrox.com的所有子域都有效)檀头。如果沒有明確設(shè)定,那么這個(gè)域會(huì)被認(rèn)作來自設(shè)置 cookie 的那個(gè)域。- 路徑(path):對于指定域中的那個(gè)路徑,應(yīng)該向服務(wù)器發(fā)送 cookie岖沛。例如,你可以指定 cookie 只有從 http://www.wrox.com/books/ 中才能訪問,那么 http://www.wrox.com 的頁面就不會(huì)發(fā)送 cookie 信息,即使請求都是來自同一個(gè)域的暑始。
- 失效時(shí)間(expires):表示 cookie 何時(shí)應(yīng)該被刪除的時(shí)間戳(也就是,何時(shí)應(yīng)該停止向服務(wù)器發(fā)送這個(gè)
cookie)。默認(rèn)情況下,瀏覽器會(huì)話結(jié)束時(shí)即將所有 cookie 刪除;不過也可以自己設(shè)置刪除時(shí)間婴削。 這個(gè)值是個(gè) GMT 格式的日期(Wdy, DD-Mon-YYYY HH:MM:SS GMT),用于指定應(yīng)該刪除 cookie 的準(zhǔn)確時(shí)間廊镜。因此,cookie 可在瀏覽器關(guān)閉后依然保存在用戶的機(jī)器上。如果你設(shè)置的失 效日期是個(gè)以前的時(shí)間,則 cookie 會(huì)被立刻刪除唉俗。- 安全標(biāo)志(secure):指定后,cookie 只有在使用 SSL 連接的時(shí)候才發(fā)送到服務(wù)器嗤朴。例如,cookie 信息只 能發(fā)送給 https://www.wrox.com,而 http://www.wrox.com 的請求則不能發(fā)送 cookie
每一段信息都作為 Set-Cookie 頭的一部分,使用分號加空格分隔每一段
Set-Cookie: name=value; expires=Mon, 22-Jan-07 07:10:24 GMT; domain=.wrox.com
*JavaScript 中的 cookie
document. cookie 屬性。
- 當(dāng)用來獲取屬性值時(shí), document.cookie 返回當(dāng)前頁面可用的(根據(jù) cookie 的域虫溜、路徑雹姊、失效時(shí)間和安全設(shè)置)所有 cookie 的字符串,一系列由分號隔開的名值對兒.
- 當(dāng)用于設(shè)置值的時(shí)候,document.cookie 屬性可以設(shè)置為一個(gè)新的 cookie 字符串。這個(gè) cookie 字
符串會(huì)被解釋并添加到現(xiàn)有的 cookie 集合中衡楞。設(shè)置 document.cookie 并不會(huì)覆蓋 cookie,除非設(shè)置的cookie 的名稱已經(jīng)存在吱雏。
*子 cookie
子 cookie 是存放在單個(gè) cookie 中的更小段的數(shù)據(jù)。也就是使用 cookie 值來存儲(chǔ)多個(gè)名稱值對 兒瘾境。子 cookie 最常見的的格式如下所示歧杏。
name=name1=value1&name2=value2&name3=value3&name4=value4
(2) IE用戶數(shù)據(jù)
在 IE5.0 中,微軟通過一個(gè)自定義行為引入了持久化用戶數(shù)據(jù)的概念。用戶數(shù)據(jù)允許每個(gè)文檔最多 128KB 數(shù)據(jù),每個(gè)域名最多 1MB 數(shù)據(jù)迷守。要使用
持久化用戶數(shù)據(jù)
,首先必須如下所示,使用 CSS 在某個(gè) 元素上指定userData 行為
:
<div style="behavior:url(#default#userData)" id="dataStore"></div>
- 使用
setAttribute()方法
保存數(shù)據(jù)犬绒。- 為了將數(shù)據(jù)提交到瀏覽器緩存中,還必須調(diào)用
save()方法
并告訴它要保存到的數(shù)據(jù)空間的名字。數(shù)據(jù)空間名字可以完全任意,僅用于區(qū)分不同的數(shù)據(jù)集兑凿。
var dataStore = document.getElementById("dataStore");
dataStore.setAttribute("name", "Nicholas");
dataStore.setAttribute("book", "Professional JavaScript");
dataStore.save("BookInfo");
- 下一次頁面載入之后,可以使用
load()方法
指定 同樣的數(shù)據(jù)空間名稱來獲取數(shù)據(jù)凯力。getAttribute()
調(diào)用了不存在的名稱或者是尚未載入的名 稱,則返回 null眨业。
dataStore.load("BookInfo");
alert(dataStore.getAttribute("name")); //"Nicholas"
alert(dataStore.getAttribute("book")); //"Professional JavaScript"
- 通過
removeAttribute()方法
明確指定要?jiǎng)h除某元素?cái)?shù)據(jù),只要指定屬性名稱。刪除之后, 必須像下面這樣再次調(diào)用 save()來提交更改沮协。
dataStore.removeAttribute("name");
dataStore.removeAttribute("book");
dataStore.save("BookInfo");
(3) Web存儲(chǔ)機(jī)制
*Storage 類型
- clear(): 刪除所有值;Firefox 中沒有實(shí)現(xiàn) 龄捡。
- getItem(name):根據(jù)指定的名字 name 獲取對應(yīng)的值。
- key(index):獲得 index 位置處的值的名字慷暂。
- removeItem(name):刪除由 name 指定的名值對兒聘殖。
- setItem(name, value):為指定的 name 設(shè)置一個(gè)對應(yīng)的值。
*sessionStorage 對象
sessionStorage
對象存儲(chǔ)特定于某個(gè)會(huì)話的數(shù)據(jù),也就是該數(shù)據(jù)只保持到瀏覽器關(guān)閉行瑞。
- sessionStorage 對象其實(shí)是 Storage 的一個(gè)實(shí)例,所以可以使用 setItem()或者直接設(shè)奸腺。
- sessionStorage 中有數(shù)據(jù)時(shí),可以使用 getItem()或者通過直接訪問屬性名來獲取數(shù)據(jù)。
- 可以通過結(jié)合 length 屬性和 key()方法來迭代 sessionStorage 中的值血久。
- 可以使用 for-in 循環(huán)來迭代 sessionStorage 中的值突照。
- 可以使用 delete 操作符刪除對象屬性,也可調(diào)用 removeItem()方法。
*globalStorage 對象
globalStorage
這個(gè)對象的目的是跨越會(huì)話存儲(chǔ)數(shù)據(jù),但有特定的訪問限制氧吐。要使用 globalStorage,首先要指定哪些域可以訪問該數(shù)據(jù)讹蘑。可以通過方括號標(biāo)記使用屬性來實(shí)現(xiàn)筑舅。
- 對 globalStorage 空間的訪問,是依據(jù)發(fā)起請求的頁面的域名座慰、協(xié)議和端口來限制的。
- 如果你事先不能確定域名,那么使用
location.host
作為屬性名比較安全翠拣。- 如果不使用 removeItem()或者 delete 刪除,或者用戶未清除瀏覽器緩存,存儲(chǔ)在 globalStorage 屬性中的數(shù)據(jù)會(huì)一直保留在磁盤上版仔。
*localStorage 對象
不能給localStorage
指定任何訪問規(guī)則;規(guī)則事先就設(shè)定好了。要訪問同一個(gè) localStorage 對象,頁面必須來自同一個(gè)域名(子域名無效),使用同一種 協(xié)議,在同一個(gè)端口上误墓。這相當(dāng)于 globalStorage[location.host]
蛮粮。
*storage 事件
這個(gè)事件的
event 對象
有以下屬性。
(1) domain:發(fā)生變化的存儲(chǔ)空間的域名谜慌。
(2) key:設(shè)置或者刪除的鍵名然想。
(3) newValue:如果是設(shè)置值,則是新值;如果是刪除鍵,則是 null。
(4) oldValue:鍵被更改之前的值畦娄。
(4) IndexedDB
*數(shù)據(jù)庫
IndexedDB
最大的特色是使用對象保存數(shù)據(jù),而不是使用表來保存數(shù)據(jù)又沾。一個(gè) IndexedDB 數(shù)據(jù)庫,就是 一組位于相同命名空間下的對象的集合。
var indexedDB = window.indexedDB || window.msIndexedDB || window.mozIndexedDB || window.webkitIndexedDB;
- 把要打開的數(shù)據(jù)庫名傳給
indexDB.open()
熙卡。如果傳入的 數(shù)據(jù)庫已經(jīng)存在,就會(huì)發(fā)送一個(gè)打開它的請求;如果傳入的數(shù)據(jù)庫還不存在,就會(huì)發(fā)送一個(gè)創(chuàng)建并打開 它的請求杖刷。總之,調(diào)用 indexDB.open()會(huì)返回一個(gè) IDBRequest 對象,在這個(gè)對象上可以添加 onerror 和 onsuccess 事件處理程序驳癌。
var request, database;
request = indexedDB.open("admin");
request.onerror = function(event){
alert("Something bad happened while trying to open: " +
event.target.errorCode);
};
request.onsuccess = function(event){
database = event.target.result;
};
(1)
event.target.result
中將有一個(gè)數(shù)據(jù)庫實(shí)例對象(IDBData- base),這個(gè)對象會(huì)保存在 database 變量中滑燃。
(2) 如果發(fā)生了錯(cuò)誤,那event.target.errorCode
中將 保存一個(gè)錯(cuò)誤碼,表示問題的性質(zhì)。
- 默認(rèn)情況下,IndexedDB 數(shù)據(jù)庫是沒有版本號的,最好一開始就為數(shù)據(jù)庫指定一個(gè)版本號颓鲜。為此, 可以調(diào)用
setVersion()方法
,傳入以字符串形式表示的版本號表窘。