久久久久久久av_日韩在线中文_看一级毛片视频_日本精品二区_成人深夜福利视频_武道仙尊动漫在线观看

HTML5移動應用開發第4章:Web Workers來加速您的移動

在本文中,您將使用最新的 Web 技術開發 Web 應用程序。這里的 大部分代碼只是 HTML、JavaScript 和 CSS — 所有 Web 開發人員的核心技術。所需的最重要的工具是用于進行測試的瀏覽器。本文大部分代碼將在最新桌面瀏覽器上運行,但也有一些例外,我們將在文章中進行說明。當然,您也必須在移動瀏覽器上測試,為此,您需要最新的 iPhone 和 Android SDKs。本文將使用 iPhone SDK 3.1.3 和 Android SDK 2.1。本文的樣例還將使用一個代理服務器來從瀏覽器訪問遠程服務。這個代理服務器是一個簡單的 Java™ servlet,但也可以使用以 PHP、Ruby 以及其他語言編寫的代理輕松替換。

移動設備上的多線程 JavaScript

對于大多數開發人員來說,多線程或并發編程并不新鮮。但是,JavaScript 并不是一種支持并發編程的語言。JavaScript 的創建者認為,對于 JavaScript 這樣旨在 Web 頁面上執行簡單任務的語言來說,并發編程容易出現問題,而且沒有必要。然而,由于 Web 頁面已經發展成為 Web 應用程序,使用 JavaScript 完成的任務的復雜程度已經大大增加,向 JavaScript 提出了與其他語言同等的要求。與此同時,使用其他支持并發編程的語言工作的開發人員經常面臨伴隨線程和 mutexes 這樣的并發原語而來的超高復雜性的困擾。實際上,最近像 Scala、Clojure 和 F# 這樣的幾種新語言已經發展,它們都有可能簡化并發性。

常用縮略詞
  • Ajax:異步 JavaScript + XML
  • API:應用程序編程接口
  • CSS:層疊樣式表
  • DOM:文檔對象模型
  • HTML:超文本標記語言
  • REST:具象狀態傳輸
  • SDK:軟件開發工具包
  • UI:用戶界面
  • URL:統一資源定位符
  • W3C:萬維網聯盟
  • XML:可擴展標記語言

Web Worker 規范不只是向 JavaScript 和 Web 瀏覽器添加并發性,而且是以一種智慧的方式添加,這種方式將增加開發人員的能力,但不會向他們提供一種會導致問題的工具。 例如,多年來,桌面應用程序開發人員一直在使用多線程來支持他們的應用程序訪問多個 I/O 資源,以避免在等待這些資源時凍結 UI。然而,當這些多線程更改共享的資源(包括 UI)時,這樣的應用程序通常會出現問題,因為這種行為可能會導致應用程序凍結或崩潰。有了 Web Workers,這種情況就不會發生。衍生線程不能訪問主 UI 線程訪問的資源。事實上,衍生線程中的代碼甚至不能與主 UI 線程執行的代碼位于同一個文件中。

您甚至必須提供相應的外部文件作為構造函數的一部分,如 清單 1 所示。

這個進程使用三個資源:

  1. 在主線程上執行的 Web 頁面 JavaScript(我稱其為頁面腳本)。
  2. Worker 對象,這是用于執行 Web Worker 函數的 JavaScript 對象。
  3. 將在新衍生的線程上執行的腳本。我稱其為 Worker 腳本。

讓我們首先看看 清單 1 中的頁面腳本。


清單 1.在頁面腳本中使用一個 Web Worker

JavaScript Code復制內容到剪貼板
  1. var worker = new Worker("worker.js");  
  2. worker.onmessage = function(message){  
  3.     // do stuff  
  4. };  
  5. worker.postMessage(someDataToDoStuffWith);  

 

在 清單 1 中,您可以看到使用 Web Workers 的三個基本步驟。首先,您創建一個 Worker 對象并向它傳遞將在新線程中執行的腳本的 URL。Worker 將執行的所有代碼都必須包含在一個 Worker 腳本中,該腳本的 URL 將被傳遞到這個 Worker 的構造函數中。這個 Worker 腳本的 URL 受到瀏覽器的同源策略的限制 — 它必須來自加載這個頁面的同一個域,該頁面已加載正在創建這個 Web Worker 的頁面腳本。

下一步是使用 onmessage 函數指定一個回調處理器函數。這個回調函數將在該 Worker 腳本執行后調用。message 是從該 Worker 腳本返回的數據,您可以隨意處理該消息。回調函數在主線程上執行,因此它能訪問 DOM。Worker 腳本在一個不同的線程內運行且不能訪問 DOM,因此,您需要將來自這個 Worker 腳本的數據返回主線程,在那里,您可以安全地修改 DOM 來更新您的應用程序的 UI。這是 Web Workers 的無共享設計的關鍵特性。

清單 1 中的最后一行展示如何通過調用 Worker 的 postMessage 函數來啟動它。這里,您傳遞一條消息(重申一下,它只是數據)給 Worker。當然,postMessage 是一個異步函數;您調用它,它就立即返回。

現在,檢查這個 Worker 腳本。清單 2 中的代碼是來自 清單 1 的 worker.js 文件的內容。


清單 2. 一個 Worker 腳本

JavaScript Code復制內容到剪貼板
  1. importScripts("utils.js");  
  2. var workerState = {};  
  3. onmessage = function(message){  
  4.      workerState = message.data;  
  5.       // do stuff with the message  
  6.     postMessage({responseXml: this.responseText});  
  7. }  

 

可以看到,這個 Worker 腳本擁有自己的 onmessage 函數。該函數在您從主線程調用 postMessage 時調用。從頁面腳本傳來的數據被傳遞到 message 對象中的 postMessage 函數。您通過檢索 message 對象的 data 屬性來訪問該數據。當您處理完 Worker 腳本中的數據時,調用 postMessage 函數將數據返回主線程。主線程也可以通過訪問它接收到的消息的 data 屬性來訪問該數據。

至此,您已經見識了 Web Workers 的這個簡單、但強大的語義。接下來,您將了解如何應用這個語義來加速移動 Web 應用程序。在此之前,有必要先討論一下設備支持。畢竟,這些是移動 Web 應用程序,且處理不同瀏覽器之間的功能的區別對于移動 Web 應用程序開發很重要。

設備支持

從 Android 2.0 開始,Android 瀏覽器就擁有了對 HTML 5 Web Worker 規范的全面支持。在撰寫本文之時,最新的 Android 設備(包括非常流行的 Motorola Droid)已配置了 Android 2.1。另外,此特性在運行 Maemo 操作系統的 Nokia 設備上的 Mozilla Fennec 瀏覽器以及 Windows Mobile 設備上受到完全支持。這里需要引起注意的遺漏是 iPhone。iPhone OS 3.1.3 和 3.2 版(在 iPad 上運行的 OS 的版本)并不支持 Web Workers。但是,此特性已在 Safari 上受到支持,因此,此特性在運行在 iPhone 上的 Mobile Safari 瀏覽器上出現應該只是一個時間問題。鑒于 iPhone 的主導地位(尤其是在美國),最好不要依賴 Web Workers 的存在,且不要只在您檢測到它們的存在時才使用它們來增強您的移動 Web 應用程序。意識到這一點后,我們來看看如何使用 Web Workers 來加速您的移動 Web 應用程序。

使用 Workers 改善性能

智能手機瀏覽器上的 Web Worker 支持很不錯,而且一直在不斷改進。這就提出了一個問題:什么時候需要在移動 Web 應用程序中使用 Workers?答案很簡單:需要完成耗時的任務的任何時候。有些示例展示了如何將 Workers 用于執行密集的數學計算,比如計算 1 萬位數的圓周率。很可能您永遠也不需要在 Web 應用程序上執行這樣一個計算,在移動 Web 應用程序上執行這種計算的幾率則更小。但是,從遠程資源檢索數據則相當常見,這也是本文示例的關注點。

在這個示例中,您將從 eBay 檢索一個 Daily Deals(每天都在變化的交易)列表。這個交易列表包含關于每筆交易的簡短信息。更詳細的信息可以通過使用 eBay 的 Shopping API 獲取。當用戶瀏覽這個交易列表選擇感興趣的商品時,您將使用 Web Workers 來預取這個附加信息。要從您的 Web 應用程序訪問所有這些 eBay 數據,您需要通過使用一個泛型代理(generic proxy)來處理瀏覽器的同源策略。一個簡單的 Java servlet 將用于這個代理,它包含在本文的代碼中,但不在這里單獨展示。相反,我們將把注意力集中在處理 Web Workers 的代碼上。清單 3 展示了這個交易應用程序的基本 HTML 頁面。

清單 3. 交易應用程序 HTML

XML/HTML Code復制內容到剪貼板
  1. <!DOCTYPE HTML>  
  2. <html>  
  3.   <head>  
  4.     <meta http-equiv="content-type" content="text/html; charset=UTF-8">  
  5.     <meta name = "viewport" content = "width = device-width">  
  6.     <title>Worker Deals</title>  
  7.     <script type="text/javascript" src="common.js"></script>  
  8.   </head>  
  9.   <body onload="loadDeals()">  
  10.     <h1>Deals</h1>  
  11.     <ol id="deals">  
  12.     </ol>  
  13.     <h2>More Deals</h2>  
  14.     <ul id="moreDeals">  
  15.     </ul>  
  16.   </body>  
  17. </html>  

 

可以看出,這是一段非常簡單的 HTML;它只是一個 shell。您使用 JavaScript 檢索數據并生成 UI。這是移動 Web 應用程序的優化設計,因為它允許將所有代碼和靜態標記緩存到設備上,用戶只需等待來自服務器的數據。注意,在 清單 3 中,一旦那個 body 加載,您就調用 loadDeals 函數,在那里,您將加載 清單 4 中的應用程序的初始數據。


清單 4. loadDeals 函數

JavaScript Code復制內容到剪貼板
  1. var deals = [];  
  2. var sections = [];  
  3. var dealDetails = {};  
  4. var dealsUrl = "http://deals.ebay.com/feeds/xml";  
  5. function loadDeals(){  
  6.     var xhr = new XMLHttpRequest();  
  7.     xhr.onreadystatechange = function(){  
  8.         if (this.readyState == 4 && this.status == 200){  
  9.                var i = 0;  
  10.                var j = 0;  
  11.                var dealsXml = this.responseXML.firstChild;  
  12.                var childNode = {};  
  13.                for (i=0; i< dealsXml.childNodes.length;i++){  
  14.                    childNode = dealsXml.childNodes.item(i);  
  15.                    switch(childNode.localName){  
  16.                    case 'Item':   
  17.                        deals.push(parseDeal(childNode));  
  18.                        break;  
  19.                    case "MoreDeals":  
  20.                        for (j=0;j<childNode.childNodes.length;j++){  
  21.                            var sectionXml= childNode.childNodes.item(j);  
  22.                            if (sectionXml && sectionXml.hasChildNodes()){  
  23.                                sections.push(parseSection(sectionXml));  
  24.                            }  
  25.                        }  
  26.                        break;      
  27.                    default:  
  28.                        break;  
  29.                    }  
  30.                }  
  31.                deals.forEach(function(deal){  
  32.                    var entry = createDealUi(deal);  
  33.                    $("deals").appendChild(entry);  
  34.                });  
  35.                loadDetails(deals);  
  36.                sections.forEach(function(section){  
  37.                    var ui = createSectionUi(section);  
  38.                    $("moreDeals").appendChild(ui);  
  39.                    loadDetails(section.deals);  
  40.                });  
  41.         }  
  42.     };  
  43.     xhr.open("GET""proxy?url=" + escape(dealsUrl));  
  44.     xhr.send(null);  
  45. }  

 

清單 4 展示了 loadDeals 函數,以及應用程序中使用的全局變量。您使用了一個 deals 數組和一個 sections 數組。它們是相關交易的附加組(例如,Deals under $10)。還有一個名為 dealDetails 的映射,其鍵是 Item IDs(來自于交易數據),其值是從 eBay Shopping API 獲取的詳細信息。

您首先調用一個代理,該代理又將調用 eBay Daily Deals REST API。這將把交易列表作為一個 XML 文檔提供給您。您解析用于進行 Ajax 調用的 XMLHttpRequest 對象的 onreadystatechange 函數中的文檔。您還使用其他兩個函數,parseDeal 和 parseSection,來將 XML 節點解析為更易于使用的 JavaScript 對象。這些函數可以在可下載的代碼樣例(參見 下載 部分)中找到,但由于它們只是令人厭煩的 XML 解析函數,因此我在這里沒有包括它們。最后,在解析了 XML 后,您還使用了另外兩個函數,createDealUi 和createSectionUi,來修改 DOM。此時,這個 UI 如 圖 1 所示。


圖 1. Mobile Deals UI
帶有樣例交易的 Mobile Deals UI 的屏幕截圖,每個交易都有一個 Show Details 按鈕 

如果您返回 清單 4,就會注意到在加載主交易之后,您對這些交易的每個部分都調用了 loadDetails 函數。在這個函數中,您通過使用 eBay Shopping API 加載每個交易的附加細節 — 但前提是瀏覽器支持 Web Workers。清單 5 展示了 loadDetails 函數。


清單 5. 預取交易細節

JavaScript Code復制內容到剪貼板
  1. function loadDetails(items){  
  2.     if (!!window.Worker){  
  3.         items.forEach(function(item){  
  4.             var xmlStr = null;  
  5.             if (window.localStorage){  
  6.                 xmlStr = localStorage.getItem(item.itemId);  
  7.             }  
  8.             if (xmlStr){  
  9.                 var itemDetails = parseFromXml(xmlStr);  
  10.                 dealDetails[itemDetails.id] = itemDetails;  
  11.             } else {  
  12.                 var worker = new Worker("details.js");  
  13.                 worker.onmessage = function(message){  
  14.                     var responseXmlStr =message.data.responseXml;  
  15.                     var itemDetails=parseFromXml(responseXmlStr);  
  16.                     if (window.localStorage){  
  17.                         localStorage.setItem(  
  18.                                         itemDetails.id, responseXmlStr);  
  19.                     }  
  20.                     dealDetails[itemDetails.id] = itemDetails;  
  21.                 };  
  22.                     worker.postMessage(item.itemId);  
  23.             }  
  24.         });  
  25.     }  
  26. }  

 

在 loadDetails 中,您首先檢查全局作用域(window 對象)中的 Worker 函數。如果該函數不在那里,那么無需做任何事。反之,您首先檢查 XML 的 localStorage 以獲取這個交易的細節。這是移動 Web 應用程序常用的本地緩存策略,本系列第 2 部分(參見 參考資料 部分的鏈接)詳細介紹過這種策略。

如果 XML 位于本地,那么您在 parseFromXml 函數中解析它并將交易細節添加到 dealDetails 對象。反之,則衍生一個 Web Worker 并使用 postMessage 向其發送 Item ID。當這個 Worker 檢索到數據并將數據發布回主線程后,您解析 XML,將結果添加到dealDetails,然后將 XML 存儲到 localStorage 中。清單 6 展示了這個 Worker 腳本:details.js。


清單 6. 交易細節 Worker 腳本

JavaScript Code復制內容到剪貼板
  1. importScripts("common.js");  
  2. onmessage = function(message){  
  3.     var itemId = message.data;  
  4.     var xhr = new XMLHttpRequest();  
  5.     xhr.onreadystatechange = function(){  
  6.         if (this.readyState == 4 && this.status == 200){  
  7.             postMessage({responseXml: this.responseText});  
  8.         }  
  9.     };  
  10.     var urlStr = generateUrl(itemId);  
  11.     xhr.open("GET""proxy?url=" + escape(urlStr));  
  12.     xhr.send(null);  
  13. }  

這個 Worker 腳本非常簡單。您使用 Ajax 調用代理,該代理又調用 eBay Shopping API。當您收到來自代理的 XML 后,使用一個 JavaScript 對象文字(object literal)將其發送回主線程。注意,即使您能夠使用來自一個 Worker 的 XMLHttpRequest,但所有信息都將返回它的 responseText 屬性,而不是它的 responseXml 屬性。這是因為這個 Worker 腳本范圍內沒有 JavaScript DOM 解析器。注意,generateUrl 函數來自 common.js 文件(見 清單 7)。您使用 importScripts 函數導入 common.js 文件。


清單 7. Worker 導入的腳本

JavaScript Code復制內容到剪貼板
  1. function generateUrl(itemId){  
  2.     var appId = "YOUR APP ID GOES HERE";  
  3.     return "http://open.api.ebay.com/shopping?callname=GetSingleItem&"+  
  4.         "responseencoding=XML&appid=" + appId + "&siteid=0&version=665"  
  5.             +"&ItemID=" + itemId;  
  6. }  

 

現在,您已經知道如何(為支持 Web Workers 的瀏覽器)填充交易細節,我們返回 圖 1 研究一下如何在應用程序中使用這種方法。注意,每筆交易旁邊都有一個 Show Details 按鈕,單擊該按鈕修改這個 UI,如 圖 2 所示。


圖 2. 顯示的交易細節
顯示交易細節的屏幕截圖,包含兩個 Golla 小包(MP3、移動電話和相機)的產品說明、圖片和價格 

這個 UI 將在您調用 showDetails 函數時顯示。清單 8 展示了這個函數。


清單 8. showDetails 函數

JavaScript Code復制內容到剪貼板
  1. function showDetails(id){  
  2.     var el = $(id);  
  3.     if (el.style.display == "block"){  
  4.         el.style.display = "none";  
  5.     } else {  
  6.         el.style.display = "block";  
  7.         if (!el.innerHTML){  
  8.             var details = dealDetails[id];  
  9.             if (details){  
  10.                 var ui = createDetailUi(details);  
  11.                 el.appendChild(ui);  
  12.             } else {  
  13.                 var itemId = id;  
  14.                 var xhr = new XMLHttpRequest();  
  15.                 xhr.onreadystatechange = function(){  
  16.                     if (this.readyState == 4 &&   
  17.                                       this.status == 200){  
  18.                         var itemDetails =   
  19.                                         parseFromXml(this.responseText);  
  20.                         if (window.localStorage){  
  21.                             localStorage.setItem(  
  22.                                               itemDetails.id,   
  23.                                               this.responseText);  
  24.                         }  
  25.                         dealDetails[id] = itemDetails;  
  26.                         var ui = createDetailUi(itemDetails);  
  27.                         el.appendChild(ui);  
  28.                     }  
  29.                 };  
  30.                 var urlStr = generateUrl(id);  
  31.                 xhr.open("GET""proxy?url=" + escape(urlStr));  
  32.                 xhr.send(null);                          
  33.             }  
  34.         }  
  35.     }  
  36. }  

 

您收到了即將顯示的交易的 ID 并切換是否顯示它。當該函數第一次調用時,它將檢查細節是否已經存儲到 dealDetails 映射中。如果瀏覽器支持 Web Workers,那么這些細節已經存儲且它的 UI 已經創建并添加到 DOM 中。如果這些細節還沒有加載,或者,如果瀏覽器不支持 Workers,那么您需要執行一個 Ajax 調用來加載此數據。這就是這個應用程序無論在有無 Workers 時都同樣能正常工作的原因。這意味著,如果 Workers 受到支持,那么數據就已被加載且 UI 將立即響應。如果沒有 Workers,UI 仍將加載,只是需要花費幾秒鐘時間。

結束語

對于 Web 開發人員來說,Web Workers 聽起來就像一種外來的新技術。但是,如本文所述,它們是非常實用的應用程序。這對于移動 Web 應用程序來說尤其正確。這些 Workers 可用于預取數據或執行其他預先操作,從而提供一個更加實時的 UI。這對于需要通過網速可能較慢的網絡加載數據的移動 Web 應用程序來說尤其正確。結合使用這種技術和緩存策略,您的應用程序的快捷反應將使您的用戶感到驚喜!

【網站聲明】本站除付費源碼經過測試外,其他素材未做測試,不保證完整性,網站上部分源碼僅限學習交流,請勿用于商業用途。如損害你的權益請聯系客服QQ:2655101040 給予處理,謝謝支持。

相關文檔推薦

這篇文章主要介紹了有關HTML5頁面在iPhoneX適配問題,需要的朋友可以參考下
本篇文章主要介紹了html5中canvas圖表實現柱狀圖的示例,本文使用canvas來實現一個圖表,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
Adobe公司出品的多媒體處理軟件產品線較多,涵蓋了音視頻編輯、圖像處理、平面設計、影視后期等領域。這篇文章主要介紹了Adobe Html5 Extension開發初體驗圖文教程,非常不錯,需要的朋
這篇文章主要介紹了基于HTML5的WebGL經典3D虛擬機房漫游動畫,需要的朋友可以參考下
這篇文章主要介紹了手機端用rem+scss做適配的詳解,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
本篇文章主要介紹了canvas 實現 github404動態效果的示例代碼,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
主站蜘蛛池模板: 欧美精品成人一区二区三区四区 | 日本小视频网站 | 天天操网 | 成人国产在线视频 | 亚洲网在线 | 国产精品久久av | 精品久久国产 | 久久精品视频亚洲 | 亚洲国产高清高潮精品美女 | 日本黄视频在线观看 | 国产精品久久久久久久久久久久久 | 国产日韩欧美电影 | 国产成人精品一区二区三区四区 | 久久久久久久网 | 隔壁老王国产在线精品 | 国产精品久久久久久久一区探花 | 另类 综合 日韩 欧美 亚洲 | 久草.com | 久久不卡 | 国产精品久久久久久久久久久久 | 久久久精品一区 | 精品视频999 | 国产精品视频网 | 国产精品久久久久永久免费观看 | 欧美极品在线 | 免费视频一区 | 欧美日韩理论 | 国产日韩一区二区 | 久久躁日日躁aaaaxxxx | 成人免费一区二区三区视频网站 | 国产精品99999 | 欧美亚洲国产精品 | 一区二区中文 | 一级欧美| 视频一区二区三区中文字幕 | 久久久久久久国产精品视频 | 99精品亚洲国产精品久久不卡 | 亚洲精品国产一区 | 欧美日韩中文字幕 | 日韩精品人成在线播放 | 欧美精选一区二区 |