開發離線Web應用須要幾個步驟:php
首先確保應用知道設備是否能上網。css
應用必須能訪問必定的資源(圖像,Javascript,CSS),這樣才能正常工做。html
HTML5新定義的屬性,這個屬性值爲true表示設備能上網,值爲false表示離線設備。這個屬性的關鍵是瀏覽器必須知道設備可否訪問網絡,從而返回正確的值。web
HTML5還定義了兩個事件:online和offline。api
當網絡從離線變爲在線或者從在線變爲離線,分別觸發着兩個事件。瀏覽器
兼容性緩存
HTML5的應用緩存,或者簡稱爲appcache,是專門爲開發離線Web應用而設計的。Appcache就是從瀏覽器緩存中分出來的一塊緩存區。安全
要想在這個緩存中保存數據,可使用一個描述文件(manifest file),列出要下載和緩存的資源。即便用戶在離線狀態下按了刷新按鈕,您的應用也會正常加載和運行。服務器
使用緩存接口可爲您的應用帶來如下三個優點:cookie
離線瀏覽 - 用戶可在離線時瀏覽您的完整網站
速度 - 緩存資源爲本地資源,所以加載速度較快。
服務器負載更少 - 瀏覽器只會從發生了更改的服務器下載資源。
清單文件必須以 text/cache-manifest MIME 類型提供
CACHE MANIFEST # 2010-06-18:v2 # Explicitly cached 'master entries'. CACHE: /favicon.ico index.html stylesheet.css images/logo.png scripts/main.js # Resources that require the user to be online. NETWORK: login.php /myapi http://api.twitter.com # static.html will be served if main.py is inaccessible # offline.jpg will be served in place of all images in images/large/ # offline.html will be served in place of all other .html files FALLBACK: /main.py /static.html images/large/ images/offline.jpg *.html /offline.html
清單可包括如下三個不一樣部分:CACHE、NETWORK 和 FALLBACK。
CACHE: 這是條目的默認部分。系統會在首次下載此標頭下列出的文件(或緊跟在 CACHE MANIFEST 後的文件)後顯式緩存這些文件。
NETWORK:
此部分下列出的文件是須要鏈接到服務器的白名單資源。不管用戶是否處於離線狀態,對這些資源的全部請求都會繞過緩存。可以使用通配符。
FALLBACK:
此部分是可選的,用於指定沒法訪問資源時的後備網頁。其中第一個 URI 表明資源,第二個表明後備網頁。兩個 URI 必須相關,而且必須與清單文件同源。可以使用通配符。
NOTE這些部分可按任意順序排列,且每一個部分都可在同一清單中重複出現。
<html manifest="example.appcache"> ... </html>
NOTE:
CACHE MANIFEST
字符串應在第一行,且必不可少。
網站的緩存數據量不得超過 5
MB。
HTTP 緩存標頭以及對經過 SSL 提供的網頁設置的緩存限制將被替換爲緩存清單(也就是加了密的網站Are https URLs encrypted)。所以,經過 https 提供的網頁可實現離線運行。
若是您要編寫的是針對 Chrome 網上應用店的應用,可以使用 unlimitedStorage
取消該限制。
若是清單文件或其中指定的資源沒法下載,就沒法進行整個緩存更新進程。在這種狀況下,瀏覽器將繼續使用原應用緩存。
applicationCache對象有一個status屬性,屬性的值是常量,表示應用緩存的狀態。
applicationCache.status
0:無緩存,即沒有與頁面相關的應用緩存
1:閒置,即應用緩存未獲得更新
2:檢查中,即正在下載描述文件並檢查更新
3:下載中,即應用緩存正在下載描述文件中指定的資源
4:更新完成,即應用緩存已經更新了資源,並且全部資源都已下載完畢,能夠經過swapCache()
來使用了
5:廢棄,即應用緩存的描述文件已經不存在了,所以頁面沒法再訪問應用緩存
checking:在瀏覽器爲應用緩存查找更新時觸發
error:在檢查更新或下載資源期間發生錯誤時觸發
noupdate:在檢查描述文件無變化時粗放
downloading:在開始下載應用緩存時資源時觸發
progress:在文件下載應用緩存資源時粗放
updateready:在頁面新的應用緩存下載完畢,並且能夠經過swapCache()時觸發。
HTTP cookie,一般叫作cookie,最初是在客戶端用於存儲會話信息的。該標準要求服務器的任意HTTP請求發送Set-Cookie HTTP頭部做爲響應的一部分,其中包含會話信息。
// HTTP響應 HTTP/1.1 200 OK Content-type: text/html Set-cookie: name=value Other-header: other-header-value // HTTP請求 GET /index.html HTTP/1.1 Cookie: name=value Other-header: other-header-value
第一段會話過程
服務器:設置name=value的cookie,並將其做爲響應頭部的一部分,發送給瀏覽器。
瀏覽器:儲存name=value的cookie並將其做爲請求頭的一部分,發送給服務器。
NOTE:
會話過程的名稱和值都是通過URL編碼的。
每一個域的cookie總數是有限的,不一樣瀏覽器之間各有不一樣。當超過單個域名限制以後還有再設置cookie,瀏覽器就會清除之前的cookie。
cookie在性質上是綁定在特定域名下的。當設定一個cookie後,再給建立它的域名發送請求時,都會包含這個cookie。
// HTTP響應 HTTP/1.1 200 OK Content-type: text/html Set-cookie: name=value; expires=Mon, 22-JAN-07 07:10:24 GMT; domain=.wrox.com;path=/;secure Other-header: other-header-value // HTTP請求 GET /index.html HTTP/1.1 Cookie: name=value Other-header: other-header-value
名稱(name):一個惟一肯定cookie的名稱,cookie的名稱必須是通過 URL編碼的。
值(value):儲存在cookie的字符串值,值必須被 URL編碼。
域:cookie對於那個域是有效的。全部向該域發送的請求中都會包含這個cookie信息。若是沒有明確設定,那麼這個域會被認做來自設置cookie的那個域。
路徑:對於指定域中的那個路徑,應該向服務器發送cookie
失效時間:表示cookie應該被刪除的那個時間戳
安全標誌:指定後,cookie只能在SSL的鏈接時,才能發送到服務器
第二段會話過程
服務器:設置name=value的cookie,同時告訴瀏覽器
它會在格林威治時間2007年1月22日7:20:24失效。
對於全部wrox.com的子域和域名下(由path參數指定的)都有效
同時經過SSL鏈接才能傳輸。
並將其做爲響應頭部的一部分,發送給瀏覽器。
瀏覽器:儲存name=value的cookie並將其做爲請求頭的一部分,發送給服務器。
Note:後四個,域/路徑/失效時間/安全標誌都是 服務器給瀏覽器的指示。以指定什麼時候該發送cookie。這些參數並不會做爲發送到服務器的標誌,名值對纔會被髮送。只有cookie的名字和值是必須的。
用來獲取屬性值時,
document.cookie
返回當前頁面可用的(根據cookie的域,路徑,失效時間和安全設置)全部的cookie的字符串。
[]()
當用來設置值得時候,
document.cookie
能夠用來設置新的cookie字符串。這個cookie字符串會用來解釋並添加到現有的cookie中。設置的值並不會覆蓋cookie,除非設置的值已經存在。
var cookieUtil = { get: function ( name ) { var cookieName = encodeURIComponent( name ) + '=', cookieStart = document.cookie.indexOf(cookieName), cookieValue = null; if( cookieStart > -1 ) { var cookieEnd = document.cookie.indexOf(';',cookieStart); if( cookieEnd === -1 ) { cookieEnd = document.length; } cookieValue = decodeURIComponent( document.cookie ).substring(cookieStart+cookieName.length, cookieEnd) } return cookieValue; }, set: function ( name, value, expires, path, domain, secure ) { var cookieText = encodeURIComponent(name) + '=' + encodeURIComponent(value); if( expires instanceof Date ) { cookieText += "; expires=" + expires.toGMTString(); } if( path ) { cookieText += '; path=' + path; } if( domain ) { cookieText += '; domain=' + domain; } if( secure ) { cookieText += '; secure'; } document.cookie = cookieText; }, unset: function ( name, path, domain, secure ) { this.set( name, '' , new Date(0), path, domain, secure) } }
爲了繞開 瀏覽器 的單域名下的cookie數限制,一種開發人員使用了一種稱爲子cookie(subcookie)的概念。子cookie是存放在單個cookie中的更小段的數據。也就是使用cookie值來儲存多個名稱值對兒。
子cookie通常以查詢字符串的格式進行格式化。而後這些值可使用單個cookie進行儲存和訪問name=name1=value1&name2=value2&name3=value3
上面展現瞭如何寫入,讀取和刪除cookie,下面展現操做子cookie的方法。
var SubCookieUtil = { get: function ( name, subName ) { var cookieValue = this.getAll( name ); if( subName ) { return result[subName]; } else { return null; } }, getAll: function ( name ) { var cookieName = encodeURIComponent( name ) + '=', cookieStart = document.cookie.indexOf( cookieName ), cookieValue = null, cookieEnd, result = {}; if( cookieStart > -1 ) { cookieEnd = document.cookie.indexOf( ';', cookieStart ); if( cookieEnd === -1 ) { cookieEnd = document.cookie.length; } } cookieValue = document.cookie.substring( cookieStart+cookieName.length, cookieEnd ); decodeURIComponent( cookieValue ); if( cookieValue.length > 0 ) { subCookies = cookieValue.split( '&' ); for( var i = 0; i < subCookies.length; i++ ) { var parts = subCookies[i].split( '=' ); result[parts[0]] = parts[1]; } return result; } else { return null; } }, set: function ( name, subName, value, expires, path, domain, secure ) { var subCookies = this.getAll( name ) || {}; subCookies[subName] = value; this.setAll( name, subCookies, expires, path, domain, secure ); }, setAll: function ( name, subCookies, expires, path, domain, secure ) { var cookieText = encodeURIComponent( name ) + '=', subCookiesParts = [], subName; for( subName in subCookies ) { if( subCookies.hasOwnProperty( subName ) ) { subCookiesParts.push( encodeURIComponent(subName) + '=' + encodeURIComponent(subCookies[subName]) ); } } if( subCookiesParts.length > 0 ) { cookieText += subCookiesParts.join('&'); if( expires instanceof Date ) { cookieText += '; expires=' + expires.toGMTString(); } if( path ) { cookieText += '; path=' + path; } if( domain ) { cookieText += '; domain=' + domain; } if( secure ) { cookieText += '; secure' } } else { cookieText += '; expires=' + (new Date(0).toGMTString()); } document.cookie = cookieText; }, unsetAll: function ( name, subCookies, expires, path, domain, secure ) { this.set( name, null, new Date(0), path, domain, secure ); }, unset: function ( name, subName, expires, path, domain, secure ) { var subCookies = this.get( name ); if( subCookies ) { delete subCookies[subName] this.setAll( name, subCookies, expires, path, domain, secure ); } } }
因爲全部的cookie都會由瀏覽器做爲請求頭髮送,因此在cookie中存儲大量信息會影響到特定域的請求性能。cookie信息越大,完成對服務器請求的時間也就越長。
cookie數據並不是存儲在一個安全環境中,其中包含的任何數據均可被他人訪問。因此必定不要在cookie中儲存重要和敏感的數據。
在IE5.0中,微軟經過一個自定義行爲引入了持久化用戶數據的概念。用戶數據容許每一個文檔最多128KB數據,每一個域名最多1MB數據。要使用持久化用戶數據,首先,必須以下所示,使用CSS在某個元素上指定userData行爲。
`<div style="behavior:url(#default#userData)" id="dataStore"></div>`
var dataStore = getElementById('dataStore'); // 寫入數據 dataStore.setAttribute('name','Nicholas'); dataStore.setAttribute('book','Professional Javascript'); dataStore.save('BookInfo'); // 獲取數據 dataStore.load('BookInfo'); // 訪問數據 console.log(dataStore.getAttribute('name')); console.log(dataStor.getAttribute('book')); // 刪除數據 dataStore.removeAttribute( 'name' ); dataStore.removeAttribute( 'book' ); dataStore.save('BookInfo');
Note:
和cookie同樣,IE用戶數據並不是安全的,全部不能存放敏感信息。
用戶數據默認是能夠跨越會話持久存在的,同時也不會過時
要訪問某個數據空間,腳本運行的頁面必須來自於同一個域名,路徑並使用與進行存儲的腳本一樣的協議。
Web Storage的兩個主要目標是
提供一種在cookie以外存儲會話數據的途徑
提供一種存儲大量能夠跨會話存在的數據的機制。
Note:與其餘客戶端儲存方案相比,WebStorage一樣也有限制,這些限制因瀏覽器圍而異。通常來講,對存儲空間大小的限制都是以每一個來源(協議,域名,端口號)爲單位的。換句話說,每一個來源都要固定大小的空間用於保存本身的數據。考慮到這個限制,就要注意分析和控制每一個來源中有多少頁面須要保存數據。
Storage提供最大的空間(因瀏覽器而異)來儲存名值對。
sessionStorage instanceof Storage // true localStorage instanceof Storage// true localStorage.__proto__ === Storage.prototype // true sessionStorage.__proto__ === Storage.prototype // true
由上可知,sessionStorage對象
與localStorage對象
都爲Storge類型的實例。所以它們均可以訪問到Storage類型的原型對象上的方法。有以下這些方法。
clear()
:刪除全部值;Firefox中沒有實現
getItem(name)
:根據指定的名字name獲取對應的值
key(index)
:得到index位置處的值得名字
removeItem(name)
:刪除由name指定的名值對
setItem(nname, value)
:爲指定的name設置一個對應的值
同時可使用length屬性判斷Storage對象中有多少名值對。但沒法判斷對象中全部數據的大小,不過IE8提供了一個remainingSpace
屬性,用於獲取還可使用的存儲空間的字節數。
Note:Storge類型只能存儲字符串。非字符串的數據在存儲以前會被轉換爲字符串。
爲每個給定的源(given origin)維持一個獨立的存儲區域,該存儲區域在頁面會話期間可用(即只要瀏覽器處於打開狀態,包括頁面從新加載和恢復)。
sessionStorage對象主要用於僅針對會話的小段數據的存儲。它儲存特定於某個會話的數據,也就是該數據只保持到瀏覽器關閉。這個對象就像會話cookie,也會在瀏覽器關閉後消失。
存儲在sessionStorage中的數據能夠跨越頁面而存在,同時若是瀏覽器支持,瀏覽器崩潰重啓後依然可用(Firefox和Webkit都支持,IE不行)。
sessionStorage對象綁定於某個服務器會話,全部當文件在本地運行的時候是不可用的。
存儲在sessionStorage的數據只能由最初給對象儲存數據的的頁面訪問到,因此對多頁面應用有限制。
// 寫入數據 sessionStorage.setItem( 'name', 'Nicholas' ); // 訪問數據 sessionStorage.getItem( 'name' ); // 迭代數據 for( var i = 0,len = sessionStorage.length; i < len; i++ ) { var key = sessionStorge.key( i ); var value = sessionStorage.getItem( key ); console.log( key + '=' + value ); } for(key in sessionStorage) { var value = sessionStorage.getItem( key ); console.log( key + '=' + value ); } // 刪除數據 sessionStorage.removeItem( 'name' );
Note:不一樣瀏覽器寫入數據的方法略有不一樣。Firefox和Webkit實現了同步寫入,全部添加到儲存空間的數據是馬上被提交的。而IE的實現是異步寫入數據,因此在設置數據和將數據寫入磁盤之間可能有一些延遲。對於少許數據而言,這個差別是能夠忽略的。對於大量數據,你會發現IE比其餘瀏覽器更快的恢復執行,由於它會跳過實際的磁盤寫入過程。
在IE8中可強制把數據寫入磁盤,以下。
// 防止代碼執行的時候,不會發生其餘磁盤寫入操做 sessionStorage.begin(); sessionStorage.name = 'Nicholas'; // 確保name的值在調用commit()以後馬上寫入磁盤 sessionStorage.commit();
localStorage 一樣的功能,可是在瀏覽器關閉,而後從新打開後數據仍然存在。
localStorage實現跨越會話存儲數據,在HTML5規範中做爲持久保存客戶端數據的方案取代了globalStorage。
規則:要訪問同一個localStorage對象,頁面必須來自於同一個域名(子域名無效),使用同一種協議,在同一個端口上。
由於localStorage是Storage的實例,全部能夠像使用sessionStorage同樣來使用它。
對Storage對象進行任何修改,都會在文檔上觸發storage事件。
storge事件對象
domain
:發生變化的儲存空間的域名
key
:設置或者刪除的鍵名
newVaule
:若是是設置值,則爲新值;若是是刪除鍵,則爲null
oldValue
:鍵被更改以前的值