HTML5 存儲API介紹
HTML5的最有趣的功能之一是本地存儲數據并且允許應用程序離線運行的功能。 共有三種不同的處理這些功能的API,如何選中其中之一取決于你希望對你將要本地存儲的數據進行怎樣處理:
- Web 存儲:適用于具有 key/value對的基本本地存儲
- 離線存儲:利用一個 manifest文件來高速緩存所有文件以便離線使用
- Web 數據庫:適用于關系型數據庫存儲
要求
預備知識:
應該熟悉JavaScript的在線和離線數據存儲技術。
需要下列產品:
Dreamweaver
Web存儲API
在用戶的機器上進行本地存儲的最基本的實現方法是利用web存儲API。 該API使用 key/value 對來支持開發人員存儲能夠被 web 應用程序訪問的基本信息和變量。 該功能的一個理想用例是用于存儲那些在用戶已經瀏覽完并且離開應用程序或已經關閉web瀏覽器之后需要永久保留的簡單數據。 例如,保存游戲狀態、保存導航位置或存儲你希望在整web應用程序中使用但你不希望使用cookie的一些特定信息(例如用戶名稱或姓名)。 類似的API還可以用于為個體會話存儲數據。 這些數據將在用戶瀏覽完離開應用程序或關閉瀏覽器之后自動清除。
當使用 web 存儲 API 時,你需要記住下列事項:
- 該存儲操作只能適用于相關的域(domain-wide),因此當使用web存儲功能保存數據時,只有在該域上的其它網站才能訪問這些數據。
- 存儲數據的大小限制是大約5M字節。 5M字節的限制是由 W3C建議的*,但該規范提供了實現細節的一些保留空間,因此,實際的字節大小取決于每個瀏覽器廠商。
核查瀏覽器支持功能
在使用web存儲API之前需要做的第一件事情是核查用戶的瀏覽器是否支持這一API:
function checkLocalStorageSupport() { try { return'localStorage'in window && window['localStorage'] !==null; } catch (e) { returnfalse; }}
你也許在上面的代碼片段中明顯地看出,web存儲使用一個名稱為localStorage 的對象,它是一個windowclass對象。 上面的代碼片段能夠核查localStorage 實際上是否是一個基于 window的對象,以及它能否返回true,以便應用程序能夠充分利用本地存儲API。
添加和返回數據
從localStorage對象中添加和返回數據與調用由本地存儲規范實現的getter和 setter方法一樣簡單。 使用localStorage 可以存儲任何類型的數據,但所有的數據必須以字符串的格式存儲于相應的存儲區域。 這意味著在將數據發送到localStorage 之前或在使用它們之后有必要對它們進行解析。 例如,為了存儲一個 JavaScript 對象,必須使用JSON 并且在檢索數據之前調用stringify() 而在檢索數據之后調用parse()。 在從localStorage 對象中檢索到數值變量之后,對它們進行解析也是如此。
在本范例中,已經建立一個單一的表單輸入,這樣,當用戶點擊Submit時,相應的數據將存儲到本地高速緩存區域。 當加載頁面時,如果數據已經存儲,則頁面將通過一個歡迎窗口顯示已存儲的信息。 下面是當用戶點擊 Submit時調用的函數:
function onClick(){ if(checkLocalStorageSupport) { window.localStorage.setItem("name",document.getElementById("name").value); }}
該函數使用localStorage對象中的setItem 方法,然后使用相應表單中的值來填充存儲高速緩存區。 當加載頁面時,應用程序利用一個onLoad 函數來核查相應的數據是否已經位于本地高速緩存區中并且將添加一個歡迎窗口。
function onLoad(){ if(checkLocalStorageSupport) { var name = window.localStorage.getItem("name"); if(name !=null) { window.document.getElementById("divName").innerHTML ="Welcome back "+ name; } }}
清除數據
盡管用戶能夠使用瀏覽器在任何時間刪除localStorage 數據,但為他們提供從應用程序自身刪除數據的選項也是合理的。localStorage 提供一個正好能夠實現這一目的clear()方法。 當用戶在你的應用程序中點擊一個復位按鈕時,將觸發下面代碼。 如果你希望從存儲區中移除一個特定條目,則你可以使用removeItem() 方法從本地存儲區中刪除一個單一key。
function onReset(){ if(checkLocalStorageSupport()) { window.localStorage.clear(); }}
處理變更
Web存儲 API 還包含一種偵聽和響應任何本地存儲變更的方法。 通過添加一個事件偵聽程序以及偵聽一個storage 事件,應用程序能夠對localStorage變更進行響應。 事件中的數據包含已更改的key的名稱、新值、老值(如果有的話)以及調用該API的頁面的URL。 可以利用下面的方式實現localStorage API的規范要求,即發起事件的會話將不能看到該事件的觸發。 這是因為規范要求該事件只能針對其它、而不是更改存儲的標簽或會話進行觸發。
為了偵聽存儲事件,首先需要做的事情是添加事件偵聽程序:
window.addEventListener("storage",onStorageChange);
然后建立onStorageChange 事件來處理存儲事件。
function onStorageChange(e) { if(e.key =="name") { alert(e.newValue +' just added their name to local storage'); } }
另外,有一個創建數據的類似API,它只對個體會話持續有效。 通過使用sessionStorage 對象,而不是localStorage對象,當用戶離開頁面時,任何保存的數據將被自動清除。 事實上,API 具有完全相同的方法,因此你可以仔細檢查并且利用sessionStorage替換localStorage,然后本地數據將被保存直到用戶關閉他們的瀏覽器或其中包含應用程序的標簽。
離線存儲
有時在用戶的機器中僅僅存儲一些數據是不能滿足要求的。 在許多情形下,整個應用程序必須離線運行,而不僅僅存儲一些數據。 對于這種使用情形,HTML5 包含了在用戶機器上高速緩存文件和資源的功能,以便瀏覽器在沒有因特網連接的情形下訪問它們。 這意味著構成web應用程序的圖像、JavaScript 文件、 HTML 文件、 CSS文件等大量數據能夠本地存儲,甚至在沒有因特網連接的情形下能夠對它們進行訪問。 這一功能的關鍵是建立一個高速緩存的Manifest文件。
使用 manifest文件
Manifest文件是頁面的根 HTML標簽的新manifest 屬性的一個組成部分。 它是一個位于web服務器上的文件,它能夠列出瀏覽器應該下載和保存以便以后使用的所有文件。 它具有一個 .manifest 擴展名并且其唯一主要的gotcha 是相應的web 服務器必須支持 .manifest mime類型,因此,應該確保駐留應用程序的該 web 服務器能夠正確提供.manifest 文件。 Manifest文件具有一個基本架構。 每個manifest 文件以CACHE MANIFEST 開頭,并且從這里開始,列出所有瀏覽器需要高速緩存的、用于離線訪問的文件。 下面是一個簡單范例,它能夠存儲一些JavaScript、一個 CSS 文件、一些圖像和 相應的HTML頁面:
CACHE MANIFESTstyle.cssofflinescript.jsimages/dreamweaver_logo.pngimages/edge_logo.png
相應的路徑均與用戶正在訪問的HTML頁面相關。 當創建高速緩存manifest文件時,你必須了解一些其它選項。 其中一個選項是絕不能高速緩存的文件的情形。 也許只有能夠在線獲得的動態腳本或某些內容才是有意義的。 高速緩存manifest文件能夠劃分為告知瀏覽器如何對某些內容進行響應的區段(section)。 通過創建一個NETWORK和列出那些絕不能高速緩存的文件,瀏覽器一定能夠忽略這些文件并且讓人們決不能離線獲得它們。
另一個情形是當用戶試圖訪問一個沒有高速緩存的頁面或某些應該高速緩存但卻沒有正確保存的內容時的情形。 高速緩存 manifest API 能夠提供一個FALLBACK 區段(section),它指向一個在上述用例中加載的頁面。 因此,當用戶試圖訪問沒有保存的某些內容時,他們將看到一條關于離線提示的消息。 下面是一個理論上的包含這些區段(section)的高速緩存Manifest文件的大概架構:
CACHE MANIFESTNETWORK:my_dynamic_script.cgiFALLBACK:my_offline_message.htmlCACHE:style.cssofflinescript.jsimages/dreamweaver_logo.pngimages/edge_logo.png
在本例中,我提供了一個帶有一個外部JavaScript 頁面和外部 CSS頁面的HTML頁面。 該HTML頁面能夠顯示一些描述一個Adobe徽標的文本,并且當你點擊相應的圖像時,JavaScript 將會為另一個徽標換出相應的圖像和文本。 下面是相應的HTML代碼,緊跟其后的是JavaScript函數:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" manifest="cache.manifest"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <title>Adobe Logos</title> <script src="offlinescript.js"></script> <link href="style.css" rel="stylesheet"/> </head> <body> <div id="textContent">This is the Edge logo:</div><br /> <img id="logo" name="logo" src="images/edge_logo.png" onclick="onLogoClick();"/> <p class="small">Click on the logo to swap it out.</p> </body> </html> // JavaScript Document function onLogoClick(e) { var currentContent = window.document.getElementById("textContent").innerHTML; if(currentContent =="This is the Edge logo:") { window.document.getElementById("textContent").innerHTML = "This is the Dreamweaver logo:"; window.document.logo.src = "images/dreamweaver_logo.png"; } else { window.document.getElementById("textContent").innerHTML = "This is the Edge logo:"; window.document.logo.src ="images/edge_logo.png"; } }
所有這些代碼的關鍵部分是帶有manifest 屬性的HTML標簽。 它是指向我在上面引用的我的cache.manifest 文件。 該manifest文件能夠指示瀏覽器下載列表中給出的所有文件。 不管用戶在瀏覽這些文件時是否下載它們,相應的瀏覽器將自動下載manifest文件中包含的所有文件。 這意味著兩個圖像都將被保存以便離線訪問,即使第二個圖像直到我與相應內容互動時才加載到頁面。 因此,只需加載該頁面一次,我即可以在離線情形下完全與它進行互動,并且兩個圖像均會旋轉。
了解事件
需要略微提到的、但卻是非常重要的離線訪問的最后部分是發生在高速緩存過程中的事件。 當瀏覽器遇到 manifest 屬性,它將在window.applicationCache 對象中觸發一系列事件。 第一個發生的事件是觸發一個checking事件。 該事件可以確定需要利用這一特別的高速緩存文件進行哪些操作。 Google Chrome 開發人員工具可以在高速緩存區保存數據時能夠全面地核查發生的事件(參見圖1)。
圖 1. 在高速緩存區保存數據時發生的事件
如果這是用戶第一次訪問該網站,則將觸發一個下載事件并且相應的web瀏覽器將仔細查看并且下載manifest文件中包含的所有資源。 它能夠讀取相應的manifest文件,確定它需要下載多少文件,然后以progress事件的形式為每個文件回送狀態更新信息。 Progress 事件包含一個已加載的變量和一個總變量,這樣開發人員能夠確定高速緩存區已經存儲的多少內容。
function onProgress(e) { var content = window.document.getElementById("loadedInfo").innerHTML; window.document.getElementById("loadedInfo").innerHTML = content +' Loaded file '+ e.loaded +' of '+ e.total; }
當完成所有文件的保存操作時,瀏覽器將觸發一個cached事件通知開發人員所有用于離線使用的文件已經成功保存。
在后面用戶訪問頁面的任何時刻,瀏覽器將核查看一看在manifest 文件中是否有內容發生改變。 如果沒有,它將觸發一個noupdate 事件,然后繼續運行。 如果其中有內容發生改變,則它將經歷與上面完全相同的過程;它將觸發一個包含一系列progress事件的downloading 事件,直到相應的文件全部更新完畢。 當該事件發生時,而不是觸發一個cached事件,瀏覽器將觸發一個updateready事件表示所有的文件已經更新并且可以離線使用。
最后一個令人發愁的事件是error 事件,它將在應用程序出現故障時觸發。 這些故障可能是文件不能正確加載,瀏覽器不能訪問cache manifest文件,或manifest列出的一個或多個文件不存在等。 為了捕捉這些故障,只需為error事件添加一個事件偵聽程序。
window.applicationCache.addEventListener("error",onError); function onError(e) { window.document.getElementById("loadedInfo").innerHTML ="Something went wrong while saving the files for offline use."; }
數據庫存儲
HTML5引入的最后一個存儲類型是目前最處于不斷變化之中的類型。 最初有一個 Web SQL規范*,但它現在已經不再使用。 現在,大多數人的精力已經轉移到Indexed Database API* 上,并且似乎這將是在關系型數據庫中存儲信息的出路。 Firefox和 Chrome 均支持IndexedDB,但由于相應的規范和支持功能均處于不斷變化之中,所以它超出本文的討論范圍。 在將來某個時候,當這一狀態改變時,我將進行相應的更新。
下一步閱讀方向
在本文中,我探索了兩種本地存儲信息的主要方法。 第一種方法以web存儲API的形式提供一些非常基本的數據存儲技術。 利用這一方法,你可以在會話之外或為一個單一會話保存名稱值對(name value pair)。 第二種方法,即應用程序cache manifest,允許開發人員在本地機器上保存所有文件,以便可以在離線情形下訪問它們。
關于HTML5存儲API的更多信息,參見下列資源: