DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> HTML基礎知識 >> HTML5詳解 >> HTML5移動應用開發第2章:移動web應用的本地存儲
HTML5移動應用開發第2章:移動web應用的本地存儲
編輯:HTML5詳解     

在本文中,您將使用最新 Web 技術開發 Web 應用程序。這裡的大多數代碼只是 Html、JavaScript 和 CSS — 任何 Web 開發人員的核心技術。需要的最重要的東西是用於測試代碼的浏覽器。本文中的大多數代碼將運行在最新的桌面浏覽器上,例外的情況會指出來。當然,還必須在移動浏覽器上進行測試,您肯定希望最新的 iPhone 和 Android SDK 支持這些代碼。本文中使用的是 iPhone SDK 3.1.3 和 android SDK 2.1。

本地存儲基礎

Web 開發人員多年來一直在嘗試將數據存儲在客戶機上。HTTP CookIEs 被濫用於此目的。開發人員將大量數據擠放在 HTTP 規范分配的 4KB 上。原因很簡單。出於各種原因,交互式 Web 應用程序需要存儲數據,並且將這些數據存儲在服務器上通常效率低下、不安全或者不適當。多年來,這個問題有了好幾種備選方法。各種各樣的浏覽器已經引入了專有存儲 API。開發人員也利用了 Flash Player 中的擴展存儲功能(通過 Javascript 實現)。類似地,Google 為各種浏覽器創建了 Gears 插件,並且它包含了存儲 API。毫不奇怪的是,一些 JavaScript 庫試圖抹平這些差異。換句話說,這些庫提供一個簡單的 API,然後檢查有哪些存儲功能(可能是一個專有浏覽器 API 或者是一個諸如 Flash 的插件)。

對 Web 開發人員來說幸運的是,Html 5 規范最終包含了一個針對本地存儲的標准,被廣泛的浏覽器所實現。事實上,該標准是最快被采納的標准,在所有主要浏覽器的最新版本中都受到支持:Microsoft®、Internet Explorer®、Mozilla Firefox、Opera、Apple Safari 和 Google Chrome。對於移動開發人員更為重要的是,它在基於 WebKit 的浏覽器(諸如 iPhone 和使用 android(版本 2.0 或更高版本)的手機中的浏覽器)以及其他移動浏覽器(比如 Mozilla 的 Fennec)中受到支持。記住這一點,我們來看一下這個 API。

Storage API

localStorage API 十分簡單。實際上,根據 HTML 5 規范,它實現了 DOM Storage 接口。差別的原因是,Html 5 指定兩個不同的對象實現該接口:localStorage 和 sessionStorage。sessionStorage 對象是一個只在會話期間存儲數據的 Storage 實現。更確切地說,只要沒有可以訪問 sessionStorage 的腳本正在運行,浏覽器就可以刪除 sessionStorage 數據。這是與 localStorage 相對的,後者跨多個用戶會話。兩個對象共享相同的 API,所以我將只著重介紹 localStorage。

Storage API 是一種經典的名/值對數據結構。您將使用的最常見的方法是 getItem(name) 和 setItem(name, value)。這些方法完全跟您預期的一樣:getItem 返回與名稱相關聯的值,如果什麼都不存在,則返回 null,而 setItem 要麼是將名/值對添加到localStorage,要麼是取代現有值。還有一個 removeItem(name),顧名思意,它從 localStorage 刪除一個名/值對(如果存在的話,否則什麼都不做)。最後,對於在所有名/值對上迭代,存在兩個 API。一個是長度屬性,給出正在存儲的名/值對的總數。對應地,一個 key(index) 方法從存儲中使用的所有名稱中返回一個名稱。

利用這些簡單的 API,可以完成大量任務,比如說個性化或跟蹤用戶行為。這些可以說對移動 Web 開發人員是重要的用例,但是還有一個更為重要的用例:高速緩存。利用 localStorage,可以在客戶機的本地機器上容易地從服務器高速緩存數據。這讓您無需等待可能緩慢的服務器回調,並且最小化了對服務器上數據的需求量。現在來看一個例子,演示了如何使用 localStorage 來獲得這種高速緩存。

例子:利用本地存儲實現高速緩存

本例建立在本系列第 1 部分中的例子之上,那時您最先開始了 t0 開發。那個例子展示了如何通過利用地理定位 API 取得用戶的位置而執行 Twitter 的本地搜索。從那個例子開始,對它進行簡化,並大大提高它的性能。首先,將那個例子簡化成不帶地理位置的 Twitter 搜索。清單 1 展示了簡化的 Twitter 搜索應用程序。


清單 1. 最基本的 Twitter 搜索

XML/Html Code復制內容到剪貼板
  1. <Html>  
  2. <head>  
  3. <meta http-equiv="Content-Type" content="text/Html; charset=UTF-8">  
  4. <meta name = "vIEwport" content = "width = device-width"/>  
  5. <title>Basic Twitter Search</title>  
  6. <script type="text/Javascript">  
  7.     function searchTwitter(){  
  8.         var query = "http://search.twitter.com/search.JSon?callback  
  9. =showResults&q=";  
  10.         query += $("kwBox").value;  
  11.         var script = document.createElement("script");  
  12.         script.src = query;  
  13.         document.getElementsByTagName("head")[0].appendChild(script);  
  14.     }  
  15.     // ui code deleted for brevity  
  16.     function showResults(response){  
  17.         var tweets = response.results;  
  18.         tweets.forEach(function(tweet){  
  19.             tweet.linkUrl = "http://twitter.com/" + tweet.from_user   
  20. + "/status/" + tweet.id;  
  21.         });  
  22.         makeResultsTable(tweets);  
  23.     }  
  24. </script>  
  25. <!--  CSS deleted for brevity -->  
  26. </head>  
  27. <body>  
  28.     <div id="main">  
  29.         <label for="kwBox">Search Twitter:</label>  
  30.         <input type="text" id="kwBox"/>  
  31.         <input type="button" value="Go!" onclick="searchTwitter()"/>  
  32.     </div>  
  33.     <div id="results">  
  34.     </div>  
  35. </body>  
  36. </Html>  

在這個應用程序中,使用了 Twitter 搜索 API 對 JSONP 的支持。用戶提交搜索時,會動態添加一個腳本標記到頁面並指定回調函數的名稱,從而進行一次 API 調用。這允許您從 Web 頁面進行一次跨域調用。一旦調用返回,回調函數(showResults)就會被調用。您添加一個鏈接 URL 到 Twitter 返回的每個 tweet,然後創建一個簡單的表格用於顯示這些 tweet。為了提速,您可以高速緩存從搜索查詢得到的結果,然後在用戶每次提交查詢時使用這些緩存的結果。首先來看如何使用 localStorage 來本地存儲 tweet。

本地保存

基本的 Twitter 搜索將從 Twitter 搜索 API 提供一組 tweet。如果您可以本地保存這些 tweet,並將它們與生成它們的關鍵詞搜索相關聯,那麼您就具有了一個有用的高速緩存。要保存 tweet,您只需要修改當對 Twitter 搜索 API 的調用返回時將被調用的 callback 函數。清單 2 展示了修改後的函數。


清單 2. 搜索和保存

JavaScript Code復制內容到剪貼板
  1. function searchTwitter(){  
  2.     var keyWord = $("kwBox").value;  
  3.     var query = "http://search.twitter.com/search.JSon?callback 
  4. =processResults&q=";  
  5.     query += keyWord;  
  6.     var script = document.createElement("script");  
  7.     script.src = query;  
  8.     document.getElementsByTagName("head")[0].appendChild(script);  
  9. }  
  10. function processResults(response){  
  11.     var keyWord = $("kwBox").value;  
  12.     var tweets = response.results;  
  13.     tweets.forEach(function(tweet){  
  14.         saveTweet(keyWord, tweet);  
  15.         tweet.linkUrl = "http://twitter.com/" + tweet.from_user + "/status/" + tweet.id;  
  16.     });  
  17.     makeResultsTable();  
  18.     addTweetsToResultsTable(tweets);  
  19. }  
  20. function saveTweet(keyWord, tweet){  
  21.     // check if the browser supports localStorage  
  22.     if (!window.localStorage){  
  23.         return;  
  24.     }  
  25.     if (!localStorage.getItem("tweet" + tweet.id)){  
  26.         localStorage.setItem("tweet" + tweet.id, JSON.stringify(tweet));  
  27.     }  
  28.     var index = localStorage.getItem("index::" + keyWord);  
  29.     if (index){  
  30.         index = JSON.parse(index);  
  31.     } else {  
  32.         index = [];  
  33.     }  
  34.     if (!index.contains(tweet.id)){  
  35.         index.push(tweet.id);  
  36.         localStorage.setItem("index::"+keyWord, JSON.stringify(index));  
  37.     }   
  38. }  

 

從第一個函數 searchTwitter 開始。這在用戶提交搜索時被調用。相對於 清單 1 做了改動的惟一的地方是 callback 函數。不只是在 tweet 返回時顯示它們,您還需要處理它們(除了顯示,還要保存它們)。因此,您指定一個新的 callback 函數 processResults。您針對每個 tweet 調用 saveTweet。您還傳遞被用於生成搜索結果的關鍵詞。這是因為您想要將這些 tweet 與該關鍵詞相關聯。

在 saveTweet 函數中,首先進行檢查,確保 localStorage 真正受到浏覽器的支持。正如前面所提到的,localStorage 在桌面和移動浏覽器中都受到廣泛支持,但是在使用這樣的新特性時進行檢查總是一個好主意。如果它不受支持,那麼您簡單地從函數返回。顯然不會保存任何東西,但是也不會報錯 — 應用程序在這種情況下只是不會具有高速緩存。如果 localStorage 受到支持,那麼首先進行檢查,看這個 tweet 是否已經存儲。如果沒有存儲,那麼使用 setItem 本地存儲它。接下來,檢索一個對應於關鍵詞的索引對象。這只是一組與關鍵詞相關聯的 tweet 的 ID。如果 tweet ID 還不是索引的一部分,那麼添加它並更新索引。

注意,在 清單 3 中保存和加載 JSON 時,您使用了 JSON.stringify 和 JSON.parse。JSON 對象(或者更確切地說,是window.JSON)是 Html 5 規范的一部分,作為一個總是存在的 原生 對象。stringify 方法將把任何 JavaScript 對象轉換成一個序列化的字符串,而 parse 方法則進行相反的操作,它從序列化的字符串表示還原 Javascript 對象。這是很必要的,因為 localStorage只存儲字符串。但是,原生 JSON 對象並不被廣泛實現為 localStorage。例如,它不出現在 iPhone(在撰寫本文時是版本 3.1.3)的最新 Mobile Safari 浏覽器上。它在最新 android 浏覽器上受支持。您可以容易地檢查它是否在那裡,如果不在,就加載一個額外的 JavaScript 文件。您可以通過訪問 json.org Web 站點(參見 參考資料),獲得原生使用的相同 JSON 對象。要本地查看這些序列化的字符串是什麼樣的,可以使用各種浏覽器工具檢查 localStorage 中為給定站點存儲的內容。圖 1 展示了一些高速緩存的 tweet,它們存儲在本地,使用 Chrome 的 Developer Tools 進行查看。


圖 1. 本地高速緩存的 tweet
一系列本地高速緩存的 tweet 的屏幕截圖(帶有 Key 和 Value 字段) 

Chrome 和 Safari 都內置了開發人員工具,可以用於查看任何保存在 localStorage 中的數據。這對於調試使用 localStorage 的應用程序非常有用。它以純文本形式展示本地存儲的鍵/值對。既然您已經開始保存來自 Twitter 的搜索 API 的 tweet,以便它們可以被用作高速緩存,所以您只需開始從 localStorage 讀取它們即可。下面來看這是如何做到的。

快速本地數據加載

在 清單 2 中,您看到了一些例子使用 getItem 方法從 localStorage 讀取數據。現在當一個用戶提交搜索時,您可以檢查高速緩存命中情況,並立即加載緩存的結果。當然,您仍將針對 Twitter 搜索 API 進行查詢,因為人們一直在產生 tweet 並添加到搜索結果。但是,通過只尋找還沒在高速緩存中的結果,現在您也有了讓查詢更為高效的方式。清單 3 展示了更新後的搜索代碼。


清單 3. 首先進行本地搜索

JavaScript Code復制內容到剪貼板
  1. function searchTwitter(){  
  2.     if ($("resultsTable")){  
  3.         $("resultsTable").innerHtml = ""; // clear results  
  4.     }  
  5.     makeResultsTable();  
  6.     var keyWord = $("kwBox").value;  
  7.     var maxId = loadLocal(keyWord);  
  8.     var query = "http://search.twitter.com/search.JSon?callback=processResults&q=";  
  9.     query += keyWord;  
  10.     if (maxId){  
  11.         query += "&since_id=" + maxId;  
  12.     }  
  13.     var script = document.createElement("script");  
  14.     script.src = query;  
  15.     document.getElementsByTagName("head")[0].appendChild(script);  
  16. }  
  17. function loadLocal(keyWord){  
  18.     if (!window.localStorage){  
  19.         return;  
  20.     }  
  21.     var index = localStorage.getItem("index::" + keyWord);  
  22.     var tweets = [];  
  23.     var i = 0;  
  24.     var tweet = {};  
  25.     if (index){  
  26.         index = JSON.parse(index);  
  27.         for (i=0;i<index.length;i++){  
  28.             tweet = localStorage.getItem("tweet"+index[i]);  
  29.             if (tweet){  
  30.                 tweet = JSON.parse(tweet);  
  31.                 tweets.push(tweet);  
  32.             }  
  33.         }  
  34.     }  
  35.     if (tweets.length < 1){  
  36.         return 0;  
  37.     }  
  38.     tweets.sort(function(a,b){  
  39.         return a.id > b.id;  
  40.     });  
  41.     addTweetsToResultsTable(tweets);  
  42.     return tweets[0].id;  
  43. }  

 

您將注意到的第一件事情是,當一個搜索被提交時,您首先調用新的 loadLocal 函數。該函數返回一個整數,即高速緩存中找到的最新 tweet 的 ID。loadLocal 函數接受一個 keyWord 作為參數,該關鍵詞也被用於在 localStorage 高速緩存中尋找相關 tweet。如果具有一個 maxId,那麼使用它來修改對 Twitter 的查詢,添加 since_id 參數。您在告訴 Twitter API 只返回比該參數中給定的 ID 新的 tweet。潛在地,這可以減少從 Twitter 返回的結果數量。您任何時候都可以為移動 Web 應用程序優化服務器調用,因為它可以真正改善慢速移動網絡上的用戶體驗。現在更仔細地來看一下 loadLocal。

在 loadLocal 函數中,您利用了存儲在前面 清單 2 中的數據結構。通過使用 getItem,您首先加載與關鍵詞相關聯的索引。如果沒找到任何索引,那麼就沒有緩存的 tweet,所以就沒有展示的東西,並且沒有可對查詢進行的優化(您返回一個 0 值以指示這一點)。如果找到一個索引,那麼您從它得到 ID 列表。這些 tweet 中的每一個都被本地高速緩存,所以您只需再次使用 getItem 方法,從高速緩存加載每一個 tweet。加載的 tweet 然後被排序。使用 addTweetsToResultsTable 函數來顯示 tweet,然後返回最新 tweet 的 ID。在本例中,得到新 tweet 的 代碼直接調用更新 UI 的函數。您可能會對此感到驚訝,因為它在存儲和檢索 tweet 的代碼與顯示它們的代碼之間創建了耦合,全都通過 processResults 函數。使用存儲事件會提供一種備選的、更少耦合的方法。

存儲事件

現在擴展示例應用程序,展示最可能具有緩存結果的前 10 個搜索條目。這可能代表用戶最常提交的搜索。清單 4 展示了一個用於計算並顯示前 10 個搜索條目的函數。


清單 4. 計算前 10 個搜索條目

JavaScript Code復制內容到剪貼板
  1. function displayStats(){  
  2.     if (!window.localStorage){ return; }  
  3.     var i = 0;  
  4.     var key = "";  
  5.     var index = [];  
  6.     var cachedSearches = [];  
  7.     for (i=0;i<localStorage.length;i++){  
  8.         key = localStorage.key(i);  
  9.         if (key.indexOf("index::") == 0){  
  10.             index = JSON.parse(localStorage.getItem(key));  
  11.             cachedSearches.push ({keyWord: key.slice(7), numResults: index.length});  
  12.         }  
  13.     }  
  14.     cachedSearches.sort(function(a,b){  
  15.         if (a.numResults == b.numResults){  
  16.             if (a.keyword.toLowerCase() < b.keyWord.toLowerCase()){  
  17.                 return -1;  
  18.             } else if (a.keyword.toLowerCase() > b.keyWord.toLowerCase()){  
  19.                 return 1;  
  20.             }  
  21.             return 0;  
  22.         }  
  23.         return b.numResults - a.numResults;  
  24.     }).slice(0,10).forEach(function(search){  
  25.         var li = document.createElement("li");  
  26.         var txt = document.createTextNode(search.keyWord + " : " + search.numResults);  
  27.         li.appendChild(txt);  
  28.         $("stats").appendChild(li);  
  29.     });  
  30. }  

 

該函數充分展示了 localStorage API。您首先得到存儲在 localStorage 中的條目的總數,然後再迭代這些條目。如果條目是索引,那麼您就解析該對象並創建一個表示您要處理的數據的對象:與索引相關聯的關鍵詞和索引中 tweet 的數量。該數據存儲在一個叫做cachedSearches 的數組中。接下來,排序 cachedSearches,將具有最多結果的搜索排在第一位,如果兩個搜索具有相同數量的緩存結果,就再使用一個不區分大小寫的字母排序。然後對於前 10 個搜索,為每個搜索創建 Html,並將它們附加到一個排好序的列表。讓我們在頁面初次加載時調用該函數,如 清單 5 所示。


清單 5. 初始化頁面

window.onload = function() { displayStats(); document.body.setAttribute("onstorage", "handleOnStorage();"); }

第一行在頁面加載時調用 清單 4 中的函數。第二次加載是變得更有趣的地方。您在這裡為 onstorage 事件設置一個事件處理程序。每當 localStorage.setItem 函數執行完成,該事件就會激活。這將允許您重新計算前 10 個搜索。清單 6 展示了該事件處理程序。


清單 6. Storage 事件處理程序

function handleOnStorage() { if (window.event && window.event.key.indexOf("index::") == 0){ $("stats").innerHtml = ""; displayStats(); } }

onstorage 事件將與窗口相關聯。它具有幾個有用的屬性:key、oldValue 和 newValue。除了這些自解釋的屬性之外,它還有一個url(更改值的頁面的 URL)和 source(包含更改值的腳本的窗口)。如果用戶具有多個到應用程序的窗口或選項卡或者甚至是 iFrames,那麼這最後兩個屬性就更有用,但是沒有哪一個在移動應用程序中特別常見。回到 清單 6,您真正需要的惟一的屬性是key 屬性。您使用該屬性來看它是不是一個已修改的索引。如果是的,那麼您重新設置前 10 名列表,並通過再次調用 displayStats函數而重新繪制它。該技術的優點是,其他函數都不需要了解前 10 名列表,因為它是自包含的。

前面 我提到過,DOM Storage(它包含 localStorage 和 sessionStorage)總體來說是一個被廣泛采納的 Html 5 特性。但是,存儲事件對於這一點來說是一個例外 — 至少在桌面浏覽器上如此。在撰寫本文時,僅有的支持存儲事件的桌面浏覽器是 Safari 4+ 和 Internet Explorer 8+。在 Firefox、Chrome 和 Opera 中不受支持。但是在移動領域,情況稍有好轉。iPhone 和 android 浏覽器的最新版都完全支持存儲事件,並且這裡給出的代碼都能在這些浏覽器中完美地運行。

結束語

作為一名開發人員,突然在客戶機上擁有巨額的存儲空間,您會覺得自己獲得了很大的解放。對於長期的 Web 開發人員來說,為做到他們多年來一直想做、卻苦於找不到好的方式來做的事情帶來了轉機。對於移動開發人員來說,則更為振奮人心,因為它真正開啟了數據的本地高速緩存。除了大大改善應用程序的性能之外,本地高速緩存對於推進移動 Web 應用程序的另一個新的令人振奮的功能 —— 離線 —— 是很關鍵的。這將是本系列下一篇文章的主題。

XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved