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

HTML5移動應(yīng)用開發(fā)第4章:Web Workers來加速您的移動

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

移動設(shè)備上的多線程 JavaScript

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

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

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

您甚至必須提供相應(yīng)的外部文件作為構(gòu)造函數(shù)的一部分,如 清單 1 所示。

這個進程使用三個資源:

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

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


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

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

 

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

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

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

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


清單 2. 一個 Worker 腳本

JavaScript Code復(fù)制內(nèi)容到剪貼板
  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 函數(shù)。該函數(shù)在您從主線程調(diào)用 postMessage 時調(diào)用。從頁面腳本傳來的數(shù)據(jù)被傳遞到 message 對象中的 postMessage 函數(shù)。您通過檢索 message 對象的 data 屬性來訪問該數(shù)據(jù)。當(dāng)您處理完 Worker 腳本中的數(shù)據(jù)時,調(diào)用 postMessage 函數(shù)將數(shù)據(jù)返回主線程。主線程也可以通過訪問它接收到的消息的 data 屬性來訪問該數(shù)據(jù)。

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

設(shè)備支持

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

使用 Workers 改善性能

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

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

清單 3. 交易應(yīng)用程序 HTML

XML/HTML Code復(fù)制內(nèi)容到剪貼板
  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 檢索數(shù)據(jù)并生成 UI。這是移動 Web 應(yīng)用程序的優(yōu)化設(shè)計,因為它允許將所有代碼和靜態(tài)標(biāo)記緩存到設(shè)備上,用戶只需等待來自服務(wù)器的數(shù)據(jù)。注意,在 清單 3 中,一旦那個 body 加載,您就調(diào)用 loadDeals 函數(shù),在那里,您將加載 清單 4 中的應(yīng)用程序的初始數(shù)據(jù)。


清單 4. loadDeals 函數(shù)

JavaScript Code復(fù)制內(nèi)容到剪貼板
  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 函數(shù),以及應(yīng)用程序中使用的全局變量。您使用了一個 deals 數(shù)組和一個 sections 數(shù)組。它們是相關(guān)交易的附加組(例如,Deals under $10)。還有一個名為 dealDetails 的映射,其鍵是 Item IDs(來自于交易數(shù)據(jù)),其值是從 eBay Shopping API 獲取的詳細信息。

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


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

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


清單 5. 預(yù)取交易細節(jié)

JavaScript Code復(fù)制內(nèi)容到剪貼板
  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 函數(shù)。如果該函數(shù)不在那里,那么無需做任何事。反之,您首先檢查 XML 的 localStorage 以獲取這個交易的細節(jié)。這是移動 Web 應(yīng)用程序常用的本地緩存策略,本系列第 2 部分(參見 參考資料 部分的鏈接)詳細介紹過這種策略。

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


清單 6. 交易細節(jié) Worker 腳本

JavaScript Code復(fù)制內(nèi)容到剪貼板
  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 調(diào)用代理,該代理又調(diào)用 eBay Shopping API。當(dāng)您收到來自代理的 XML 后,使用一個 JavaScript 對象文字(object literal)將其發(fā)送回主線程。注意,即使您能夠使用來自一個 Worker 的 XMLHttpRequest,但所有信息都將返回它的 responseText 屬性,而不是它的 responseXml 屬性。這是因為這個 Worker 腳本范圍內(nèi)沒有 JavaScript DOM 解析器。注意,generateUrl 函數(shù)來自 common.js 文件(見 清單 7)。您使用 importScripts 函數(shù)導(dǎo)入 common.js 文件。


清單 7. Worker 導(dǎo)入的腳本

JavaScript Code復(fù)制內(nèi)容到剪貼板
  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. }  

 

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


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

這個 UI 將在您調(diào)用 showDetails 函數(shù)時顯示。清單 8 展示了這個函數(shù)。


清單 8. showDetails 函數(shù)

JavaScript Code復(fù)制內(nèi)容到剪貼板
  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 并切換是否顯示它。當(dāng)該函數(shù)第一次調(diào)用時,它將檢查細節(jié)是否已經(jīng)存儲到 dealDetails 映射中。如果瀏覽器支持 Web Workers,那么這些細節(jié)已經(jīng)存儲且它的 UI 已經(jīng)創(chuàng)建并添加到 DOM 中。如果這些細節(jié)還沒有加載,或者,如果瀏覽器不支持 Workers,那么您需要執(zhí)行一個 Ajax 調(diào)用來加載此數(shù)據(jù)。這就是這個應(yīng)用程序無論在有無 Workers 時都同樣能正常工作的原因。這意味著,如果 Workers 受到支持,那么數(shù)據(jù)就已被加載且 UI 將立即響應(yīng)。如果沒有 Workers,UI 仍將加載,只是需要花費幾秒鐘時間。

結(jié)束語

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

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

相關(guān)文檔推薦

這篇文章主要介紹了有關(guān)HTML5頁面在iPhoneX適配問題,需要的朋友可以參考下
本篇文章主要介紹了html5中canvas圖表實現(xiàn)柱狀圖的示例,本文使用canvas來實現(xiàn)一個圖表,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
Adobe公司出品的多媒體處理軟件產(chǎn)品線較多,涵蓋了音視頻編輯、圖像處理、平面設(shè)計、影視后期等領(lǐng)域。這篇文章主要介紹了Adobe Html5 Extension開發(fā)初體驗圖文教程,非常不錯,需要的朋
這篇文章主要介紹了基于HTML5的WebGL經(jīng)典3D虛擬機房漫游動畫,需要的朋友可以參考下
這篇文章主要介紹了手機端用rem+scss做適配的詳解,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
本篇文章主要介紹了canvas 實現(xiàn) github404動態(tài)效果的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
主站蜘蛛池模板: 一区二区三区四区在线视频 | 日本一区视频在线观看 | 午夜不卡一区二区 | 色狠狠一区 | 久久久久久国产精品 | 欧美久久久久久 | 在线免费观看日本 | 中文字幕成人 | 91麻豆精品国产91久久久更新资源速度超快 | 日韩淫片免费看 | 午夜精品久久久久久久久久久久 | 成人在线网址 | 一区二区视频在线观看 | 日本精品视频在线 | 日日夜夜影院 | 国产在线一区二区 | 国产精品美女久久久免费 | 97天天干 | 久久精品国产久精国产 | 精精国产xxxx视频在线 | 日韩精品一区二区在线观看 | 国产91亚洲精品一区二区三区 | 91亚洲精品在线观看 | www.中文字幕av | 国产精品久久久久久238 | 国产精品久久久久久久久久免费看 | 天天干狠狠操 | 高清人人天天夜夜曰狠狠狠狠 | 男女视频在线观看免费 | 久久精品国产久精国产 | 久久久久一区 | 国产精品欧美大片 | 欧美1区 | 国产免费让你躁在线视频 | 国产成人叼嘿视频在线观看 | 亚洲毛片在线 | 日韩一区二区三区在线视频 | 四虎影视免费观看 | 国产一区不卡 | 成人免费福利 | 国产精品日产欧美久久久久 |