<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                &emsp;&emsp;現如今,在呈現一個頁面時,在瀏覽器中會打開眾多進程,包括瀏覽器、渲染、插件、GPU、網絡等進程。 &emsp;&emsp;瀏覽器進程負責存儲、界面、下載等管理。在渲染進程中,運行著熟知的主線程、合成線程、JavaScript 解釋器、排版引擎等。 &emsp;&emsp;而呈現一個頁面大致可分為 4 個步驟: 1. 瀏覽器進程處理用戶在地址欄的輸入,然后將 URL 發送給網絡進程。 2. 網絡進程發送 URL 請求,在接收到響應數據后進行解析,接著轉發給瀏覽器進程。 3. 瀏覽器進程收到響應后,發送“提交導航”消息到渲染進程。 4. 渲染進程開始接收網絡進程發送的數據,并進行文檔渲染。 &emsp;&emsp;基于上述步驟可以聯想到,呈現的優化分為兩部分:資源和渲染。 &emsp;&emsp;像上一節的[圖像](https://www.cnblogs.com/strick/p/17080155.html)其實也屬于資源部分,只是內容比較多就單獨創建了章節。 &emsp;&emsp;本文所用的示例代碼已上傳至[Github](https://github.com/pwstrick/pe)。 ## 一、資源 &emsp;&emsp;HTTP Archive 關于 2022 年頁面大小的[報告](https://almanac.httparchive.org/en/2022/page-weight)指出,按大小升序后,排在中間位置的移動頁面大概有 70 個請求。 &emsp;&emsp;包括 22 個圖像、21 個腳本、7 個 CSS以及 2 個 HTML,腳本和 CSS 占了 40% 的請求。 &emsp;&emsp;除了對這些資源進行尺寸優化之外,還可以對它們的加載進行優化。 **1)優先級** &emsp;&emsp;瀏覽器會給不同資源給予不同的請求優先級。 &emsp;&emsp;以 Chrome 為例,分為多個等級,包括 Highest 、High、Low 和 Lowest 等,如下圖所示。 :-: ![](https://img.kancloud.cn/0f/1b/0f1bfa58a579fae278c7bf0229fa3b82_1580x606.png =800x) &emsp;&emsp;HTML 和 head 元素中的 CSS 優先級是最高的,head 元素中的腳本是高優先級,異步請求的腳本是低優先級。 &emsp;&emsp;若優先級不符合預期,可以通過一些配置修改優先級,例如為 script 元素聲明 async/defer,它的優先級就會變成低。 &emsp;&emsp;在 img 元素中,新增了一個[fetchPriority](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/fetchPriority)屬性(如下所示),當值是 high 時,意味著這是一張重要的圖像,瀏覽器會提升優先級立即開始請求。 ~~~html <img src="hero.png" fetchpriority="high" /> ~~~ **2)link 元素** &emsp;&emsp;link 元素常用來加載 CSS 文件,但它還支持些其他功能,接下來會一一介紹。 &emsp;&emsp;當 link 的 rel 屬性值為[preload](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel/preload)時,就能預加載資源,如下所示。 ~~~html <link rel="preload" href="demo.js" as="script" /> ~~~ &emsp;&emsp;as 屬性是告知瀏覽器加載的資源類型,包括 style、script、font、image 等。 &emsp;&emsp;預加載可提升資源的優先級,不過當資源在幾秒后未使用時,瀏覽器會發出告警。 &emsp;&emsp;2023-11-20 高版本的瀏覽器已經原生支持 JavaScript 模塊化(即 import 語法),這意味著可以在瀏覽器內直接基于模塊編寫 JavaScript 而不用編譯和打包。 &emsp;&emsp;但是模塊依賴項會帶來加載問題,因為瀏覽器需要先等待模塊加載,然后才能找到其依賴項。 &emsp;&emsp;從 Chrome 66 開始,rel 屬性支持一個新的關鍵字:[modulepreload](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel/modulepreload),解決上述問題。 &emsp;&emsp;它用于聲明預加載模塊,也就是預加載依賴項,以便瀏覽器提前知道相關文件。 &emsp;&emsp;當 link 的 rel 屬性值為[preconnect](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel/preconnect)時,就能預連接站點,如下所示。 ~~~html <link rel="preconnect" href="https://www.pwstrick.com" /> ~~~ &emsp;&emsp;另一個與連接相關的類型是[dns-prefetch](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel/dns-prefetch)(如下所示),用來處理 DNS 查詢,即 DNS 預解析。 ~~~html <link rel="dns-prefetch" href="https://www.pwstrick.com" /> ~~~ &emsp;&emsp;當 link 的 rel 屬性值為[prefetch](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel/prefetch)時,就能預提取資源,如下所示。 ~~~html <link rel="prefetch" href="demo.js" /> ~~~ &emsp;&emsp;預提取會讓資源的優先級降為最低,用于讓某些非關鍵資源提前請求,可為用戶的下一步交互做準備。 &emsp;&emsp;2023-03-23 當 link 的 rel 屬性值為[prerender](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel/prerender)時,就能預渲染指定的網站,如下所示。 ~~~html <link rel="prerender" href="https://www.pwstrick.com" /> ~~~ &emsp;&emsp;不過,該參數的兼容性有限,Safari 和 Firefox 都不支持,如下圖所示。 :-: ![](https://img.kancloud.cn/48/25/48257a005353368f95810aeeca491d1d_1357x221.png =800x) &emsp;&emsp;有個名為[Tachyon](https://fasterthanlight.net/)的開源庫,基于 prerender,對頁面之間的導航進行了提速。 &emsp;&emsp;在用戶將鼠標移動到鏈接時,會通過創建 link 元素,并賦予 prerender,實現指定地址的預渲染。 **3)script 元素** &emsp;&emsp;延遲(defer)和異步(async)的出現是為了解決 script 元素阻塞 HTML 解析的問題,下圖描繪了 script 元素的 3 種運行機制。 :-: ![](https://img.kancloud.cn/f6/4c/f64c9584717884ad8fe052240c5b1e33_1581x245.png) &emsp;&emsp;第一行是默認的運行機制,在解析HTML文檔時,一遇到 script 元素就停止解析,改成下載外部腳本,然后執行腳本,執行完后才會繼續解析。 &emsp;&emsp;第二行是使用了 defer 屬性后的運行機制,HTML 文檔的解析和外部腳本的下載是同時進行的,解析完后才會執行腳本。 &emsp;&emsp;第三行是使用了async 屬性后的運行機制,HTML 文檔的解析和外部腳本的下載也是同時進行,但下載完后就開始執行腳本,執行完后才會繼續解析。 &emsp;&emsp;2023-11-20 有個庫叫 [Partytown.js](https://github.com/BuilderIO/partytown),比較有意思,可以將第三方腳本遷移到 Web Worker 中執行,防止阻塞主線程,不過這還只是個測試性的庫。 **4)數據預請求** &emsp;&emsp;在客戶端的 WebView 中,每次請求后端接口大概要花 100~200ms,如果把這段時間省下來,那么也能減少白屏時間。 &emsp;&emsp;數據預請求是將請求時機由業務發起提前到用戶點擊時,并行發送數據請求,縮短數據等待時間,如下圖所示。 :-: ![](https://img.kancloud.cn/be/db/bedbd7b2a749a61f9cd1e7ea547f3f09_1274x372.png =600x) &emsp;&emsp;這種改造需要客戶端配合,現在簡單介紹下我們公司當時實現的方案,流程圖如下所示。 :-: ![](https://img.kancloud.cn/9b/f8/9bf87beac1a3f77c86445fe860c811ac_705x750.png =600x) &emsp;&emsp;首屏數據的接口信息,可以通過一些配置關聯起來,比如一個單獨的配置接口。 &emsp;&emsp;客戶端在拿到數據后,就會緩存到一個全局變量中,等待腳本讀取。 &emsp;&emsp;注意,到底是客戶端先拿到數據,還是網頁先拿到,這個無法確定,并且預請求只能以 get 方法通信。 &emsp;&emsp;具體的實現方案如下: * 客戶端分析出當前 URL 中的路徑和參數,其中 refresh 參數(有的話)是一個時間戳(秒),這個參數用來控制客戶端是否需要重新請求配置接口。 * 當分析的 URL 參數中無 refresh 字段時,訪問 https://xxx.com/settings 接口,并將URL路徑、客戶端默認帶的參數(包含用戶ID等)和 URL 本身的參數全部傳遞過來(如下所示),然后本地緩存。 ~~~ https://xxx.com/settings?path=game%2Fstrick&uid=xxxxx&refresh=1618451992 ~~~ * 客戶端會將 settings 接口的響應數據緩存到本地,而 key 就是當前 URL,也就是說 URL 不變的話,默認就不會去請求 settings 接口。若要穿透緩存,那么加上 refresh 參數,賦一個與之前不同的值即可。 * settings 接口返回的 JSON 格式,包含 urls 字段(如下所示),是個數組,由接口集合組成,已經拼接好參數。 ~~~ { "urls": [ "http://xxx.com/xx/xx?id=2", "http://xxx.com/yy/yy?uid=1" ] } ~~~ * 客戶端將讀取到的數據注入到 WebView 的全局對象中,可以用全局變量同步讀取,名字可自行約定,例如叫 TheLClientResponse,讀取方式:window.TheLClientResponse,JSON 格式如下,其中 key 是 api 的路徑,如果無數據可以返回 null。 ~~~ { "xx/xx": { code: 0, msg: "test", data: { list: [] } }, "yy/yy": { code: 0, msg: "test", data: { list: [] } } } ~~~ **5)字體** &emsp;&emsp;CSS3 提供了[@font-face](https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face)規則允許為網頁指定自定義字體,其聲明和使用如下所示。 ~~~css @font-face { font-family: "iconfont"; src: url("../font/iconfont.woff2") format("woff2"), url("../font/iconfont.woff") format("woff"), url("../font/iconfont.ttf") format("truetype"); } .iconfont { font-family: "iconfont"; } ~~~ &emsp;&emsp;上述字體來源于[iconfont](https://www.iconfont.cn/),為了兼容性考慮,往往會提供多個格式的字體。 &emsp;&emsp;其中 ttf 是一種未壓縮的格式,另外兩種內部都做過壓縮。在 2022 年大概有[75%~78%](https://almanac.httparchive.org/en/2022/fonts#performance)的網頁在使用 woff2 格式的字體。 &emsp;&emsp;使用字體除了改變文字外形之外,還有一種普遍用法是用來顯示 icon 小圖標。 &emsp;&emsp;2023-11-27 因為這樣就能讓 icon 成為矢量圖,所以縮放既不會變形,也不會影響流量。 &emsp;&emsp;CSS3 提供了[font-display](https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display)屬性用于指定字體的渲染方式,在 @font-face 中聲明,2022 年用的最多的值是 swap。 &emsp;&emsp;swap 會讓文字先按瀏覽器默認的字體展示,當字體加載完成后,再將其替換掉。在慢網中,會看到字體的前后變化。 &emsp;&emsp;所以應該盡快加載字體,才能讓用戶享受到最優的體驗。 &emsp;&emsp;瀏覽器在解析 CSS 文件時,并不會馬上下載 @font-face 中的字體文件。 &emsp;&emsp;只有當發現 HTML 中有非空節點使用該字體時,才會開始下載。 &emsp;&emsp;如果要提早下載,那么可以使用預加載,如下所示。 ~~~html <link rel="preload" href="../../assets/font/dakai.woff2" as="font" crossorigin="anonymous"/> ~~~ &emsp;&emsp;crossorigin 屬性是必填的,表示允許跨域,若省略,就會有告警。 &emsp;&emsp;還有一種優化方法是提取字體的子集(即有選擇性的將需要的字符組合在一起),減小字體文件的尺寸,像圖標就比較適合這樣自定義。 ## 二、渲染過程 &emsp;&emsp;瀏覽器的渲染過程大致可分為 8 個階段,如[下圖](https://cabulous.medium.com/how-browser-works-part-i-process-and-thread-f63a9111bae9)所示。 :-: ![](https://img.kancloud.cn/8a/44/8a44a4900621fb22fef2b83ec0087153_1752x621.png =600x) &emsp;&emsp;下面的 1~5 步涉及主線程(main thread),6~8 步涉及合成線程(compositor thread)。 1. 將 HTML 解析成 DOM 樹,并將其存儲在內存中,同時下載解析到的資源。 2. 將 CSS 解析成樣式表(style sheets),即生成 CSSOM,在此階段會計算節點樣式,并把相對的值和單位都轉換成像素。 3. 通過 DOM 和樣式表生成布局樹(layout tree),在此階段會計算元素的尺寸和坐標,并且在樹中不包含隱藏元素,但會包含 CSS 中創建的內容。 4. 對布局樹進行分層,生成分層樹(layer tree),可控制繪畫順序,裁剪元素內容,CSS 中的 transform、z-index、will-change 等屬性都與層相關。 5. 通過布局樹和分層樹生成繪制列表,并將其提交給合成線程。 6. 通過繪制列表和圖層生成圖塊(tile),因為渲染所有圖塊會比較昂貴,所以會劃分優先級,例如視口中的可見圖塊優先級會高。 7. 圖塊在提交到光柵化(raster)線程池后,會被轉移到 GPU 中,加速光柵化處理,即轉換成位圖(bitmap),最終結果會存儲在 GPU 內存中。 8. GPU 將位圖傳送回合成線程后,就會生成合成幀,處理完所有位圖后,合成器線程向瀏覽器發送 Draw Quad 命令,開始在屏幕上顯示頁面。 &emsp;&emsp;雖然這 8 個階段的執行過程比較復雜,但是在現代瀏覽器中,它們會在 1/60 秒(即 16.67 毫秒)內完成,下圖描述了整個渲染過程。 :-: ![](https://img.kancloud.cn/21/48/214839522706fd4b654c03153a872a43_1230x1534.png =600x) &emsp;&emsp;優化渲染過程的核心就是縮短某個階段的執行時間,或者直接跳過某些階段。 **1)流式渲染** &emsp;&emsp;HTTP/1.1 協議支持分塊傳輸編碼(chunked transfer encoding),允許服務器將網頁數據分成多塊后再進行傳輸。 &emsp;&emsp;在響應頭中設置 Transfer-Encoding: chunked 就會啟用分塊傳輸編碼的響應格式。 &emsp;&emsp;瀏覽器在知道 HTML 會被流式返回后,就不用等到 HTML 下載完成后再開始解析了。 &emsp;&emsp;不過,目前流行的客戶端渲染(Client Side Render)其實并不需要專門的流式渲染,因為 HTML 的內容本來就少。 &emsp;&emsp;若改成服務端渲染(Server Side Render),那就可根據實際情況進行流式渲染的優化了。 &emsp;&emsp;具體的實現過程,本文不再贅述,可參考網上相關的方案,例如 Vue SSR 指南中的[流式渲染](https://v2.ssr.vuejs.org/zh/guide/streaming.html)。 **2)DOM** &emsp;&emsp;HTML 在被解析時,一旦遇到 JavaScript,那么就會被阻塞,如下圖所示。 :-: ![](https://img.kancloud.cn/2c/3c/2c3c8e0e4602d9105487c5098894c368_720x465.png =600x) &emsp;&emsp;當遇到外部腳本時,還會停止 DOM 樹的構建,轉由網絡進程去請求 JavaScript 腳本地址。 &emsp;&emsp;CSS 本身并不會阻塞 DOM 樹的構建,但在與 JavaScript 結合使用時,會出現阻塞。 &emsp;&emsp;在下面的示例中,JavaScript 會修改 demo.css 文件中的樣式。 ~~~html <link rel="stylesheet" href="demo.css" /> <div id='root'>內容</div> <script> const root = document.getElementById('root'); root.style.color = 'red'; </script> ~~~ &emsp;&emsp;主線程在執行腳本之前,需要先計算節點樣式(即解析 CSS 文件),因此 DOM 樹就無法被繼續構建了。 &emsp;&emsp;若要優化 DOM 樹的構建,除了盡量避免上述不科學的寫法之外,還可以從兩方面入手:減少關鍵資源請求的數量和大小。 &emsp;&emsp;所謂關鍵資源(key resource),更確切的說就是網頁首屏的核心資源,沒有它們,那么首屏將無法正確的呈現。 &emsp;&emsp;減少資源的請求數量可以通過 2 個方法: * 將 CSS 或 JavaScript 內聯到 HTML 結構中,例如移動端的屏幕適配腳本就比較適合內聯。 * 腳本元素可以增加 async 或 defer 的標記,具體可以參考上一節的 script 元素。 &emsp;&emsp;關鍵資源的大小除了進行壓縮外,就是只提取首屏需要的代碼。 &emsp;&emsp;將其他部分的代碼合并到另一個文件,待需要時再加載,或者使用上一節所說的預提取。 **3)重排和重繪** &emsp;&emsp;重排(reflow)也叫回流,是指修改元素的幾何屬性后引起的重新渲染,涉及 7 個階段,如下圖所示,修改了元素的高度。 :-: ![](https://img.kancloud.cn/f3/d9/f3d91d50d5423396f9e48d984edc8d3e_2043x826.png =600x) &emsp;&emsp;觸發重排的情況有添加或刪除可見的元素、修改位置、邊距或內容等。 &emsp;&emsp;重繪(repaint)是指修改元素的背景顏色后引起的重新渲染,但與重排不同,重繪將直接進入 Paint 階段,如下圖所示。 :-: ![](https://img.kancloud.cn/37/58/37580acca37444f23b38f16c63e79199_2041x853.png =600x) &emsp;&emsp;重排和重繪都會降低渲染性能,因為它們都發生在主線程中,并且布局、分層和繪制 3 個階段的計算過程比較昂貴。 &emsp;&emsp;當在腳本中獲取元素的尺寸、位置等排版相關的信息時,就有可能觸發強制重排,例如調用 offsetTop、clientWidth、getComputedStyle() 等屬性或方法。 &emsp;&emsp;優化它們的方式包括使用 cssText 或 CSS 類修一次性修改多個 CSS 屬性,批量修改 DOM,例如使用文檔片段 fragment、先隱藏元素再顯示等。 &emsp;&emsp;在眾多的 CSS 屬性中,有兩個 CSS 屬性(transform 和 opacity)可以避開重排和重繪,直接進入合成階段。 &emsp;&emsp;例如用 transform 屬性實現的元素變化,就不會占用主線程,而是由合成線程處理,如下圖所示。 :-: ![](https://img.kancloud.cn/4c/c5/4cc5a8c5d6f854d63898bf93e7ae17ec_2041x834.png =600x) &emsp;&emsp;值得一提的是,早期在腳本中實現動畫,都會借助定時器,但定時器無法精確的配置動畫幀之間的時間間隔。 &emsp;&emsp;按屏幕刷新率為每秒 60 次計算,那么理論上每幀的間隔約等于是 16.67 毫秒。 &emsp;&emsp;但實際情況比較復雜,間隔不一定是這個值,有可能出現丟幀,從而造成動畫不夠平滑流暢。 &emsp;&emsp;為了解決動畫問題,瀏覽器提供了[requestAnimationFrame()](https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame)方法,在每一幀的開始執行配置的回調。 &emsp;&emsp;注意,只有當瀏覽器 GPU 生成位圖和屏幕顯示位圖保持同步時,才會觸發 requestAnimationFrame() 的回調。 &emsp;&emsp;在下面的示例中,讓絕對定位的 span 元素通過 requestAnimationFrame() 向右偏移。 ~~~html <span id='container' style="position:absolute">內容</span> <script> let left = 0; const frame = () => { const container = document.getElementById('container'); container.style.left = `${left++}px`; if (left > 100) return; requestAnimationFrame(frame); }; requestAnimationFrame(frame); </script> ~~~ &emsp;&emsp;注意,requestAnimationFrame() 也是運行在主線程中,如果主線程繁忙,那么也有可能延遲回調,造成動畫的卡頓。 &emsp;&emsp;并且如果其回調比較耗時(超過一幀),那么就會阻礙后續的任務。 **4)離屏渲染** &emsp;&emsp;2023-11-20 離屏渲染相當于開辟一個緩沖區,將屏幕外的內容提前繪制好,在滾動或需要時就能直接呈現對應內容。 &emsp;&emsp;一種實現方式是維護兩個 Canvas,當前渲染的 Canvas 與隱藏的緩存 Canvas 兩者交替繪制,這不僅復雜,并且還要消耗更多的計算資源。 &emsp;&emsp;另一種是使用 [OffscreenCanvas](https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas) 實現真正的離屏,這是一個實驗中的新功能,提升 Canvas 在 2D/3D 繪圖時的渲染性能和使用體驗。 &emsp;&emsp;與 Canvas 只能在主線程中執行不同,OffscreenCanvas 既可以在主線程中執行,也可以在 Web Worker 中執行,這讓不影響主線程的離屏渲染成為可能。 ## 總結 &emsp;&emsp;本文的第一章節詳細描述了資源的優化,并在開篇指出資源都存在著優先級,瀏覽器會按優先級進行請求。 &emsp;&emsp;預加載可提升資源的優先級,預提取可降低資源的優先級,預連接可提前進行 TCP 連接或 DNS 查詢。 &emsp;&emsp;script 元素有延遲和異步兩種運行機制,可有效地防止 HTML 解析的阻塞。 &emsp;&emsp;數據預請求需要與客戶端配合,本文給出了一份解決方案可供參考。 &emsp;&emsp;自定義字體在頁面開發中有著廣泛的應用,常用的優化手段是預加載和減小尺寸。 &emsp;&emsp;在第二章節中詳細分析了瀏覽器的渲染過程,這個過程大致可分為 8 個階段。 &emsp;&emsp;圍繞這些階段,引出了流式渲染、DOM 樹構建的優化。 &emsp;&emsp;在重排和重繪中,詳細說明了它們影響的階段,并且列舉了觸發原因,以及優化手段。 &emsp;&emsp;最后提到了合成動畫,并且對比了 JavaScript 動畫的兩種實現方式。 ***** > 原文出處: [博客園-前端性能精進](https://www.cnblogs.com/strick/category/2267607.html) [知乎專欄-前端性能精進](https://www.zhihu.com/column/c_1610941255021780992) 已建立一個微信前端交流群,如要進群,請先加微信號freedom20180706或掃描下面的二維碼,請求中需注明“看云加群”,在通過請求后就會把你拉進來。還搜集整理了一套[面試資料](https://github.com/pwstrick/daily),歡迎閱讀。 ![](https://box.kancloud.cn/2e1f8ecf9512ecdd2fcaae8250e7d48a_430x430.jpg =200x200) 推薦一款前端監控腳本:[shin-monitor](https://github.com/pwstrick/shin-monitor),不僅能監控前端的錯誤、通信、打印等行為,還能計算各類性能參數,包括 FMP、LCP、FP 等。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看