精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

120 行代碼幫你了解 Webpack 下的 HMR 機制

開發 前端
在使用Webpack Dev Server以后 可以讓我們在開發工程中 專注于 Coding, 因為它可以監聽代碼的變化 從而實現打包更新,并且最后通過自動刷新的方式同步到瀏覽器,便于我們及時查看效果。

[[405493]]

本文轉載自微信公眾號「微醫大前端技術」,作者朱海華。轉載本文請聯系微醫大前端技術公眾號。

HMR 的背景

在使用Webpack Dev Server以后 可以讓我們在開發工程中 專注于 Coding, 因為它可以監聽代碼的變化 從而實現打包更新,并且最后通過自動刷新的方式同步到瀏覽器,便于我們及時查看效果。但是 Dev Server 從監聽到打包再到通知瀏覽器整體刷新頁面 就會導致一個讓人困擾的問題 那就是 無法保存應用狀態 因此 針對這個問題,Webpack 提供了一個新的解決方案 Hot Module Replacement

HMR 簡單概念

Hot Module Replacement 是指當我們對代碼修改并保存后,Webpack 將會對代碼進行重新打包,并將新的模塊發送到瀏覽器端,瀏覽器用新的模塊替換掉舊的模塊,以實現在不刷新瀏覽器的前提下更新頁面。最明顯的優勢就是相對于傳統的live reload而言,HMR 并不會丟失應用的狀態,提高開發效率。在開始深入了解 Webpack HMR 之前 我們可以先簡單過一下下面這張流程圖

HRM 流程概覽

1597240262452-5ecbaec0-6245-4ed5-9195-59c7a38e8b24.png

Webpack Compile: watch 打包本地文件 寫入內存

Boundle Server: 啟一個本地服務,提供文件在瀏覽器端進行訪問

HMR Server: 將熱更新的文件輸出給 HMR Runtime

HRM Runtime: 生成的文件,注入至瀏覽器內存

Bundle: 構建輸出文件

HMR 入門體驗

開啟 HMR 其實也極其容易 因為 HMR 本身就已經集成在了 Webpack 里 開啟方式有兩種

  1. 直接通過運行 webpack-dev-server 命令時 加入 --hot參數 直接開啟 HMR
  2. 寫入配置文件 代碼如下
  1. // ./webpack.config.js 
  2. const webpack = require('webpack'
  3. module.exports = { 
  4.   // ... 
  5.   devServer: { 
  6.     // 開啟 HMR 特性 如果不支持 MMR 則會 fallback 到 live reload 
  7.     hot: true
  8.   }, 
  9.   plugins: [ 
  10.     // ... 
  11.     // HMR 依賴的插件 
  12.     new webpack.HotModuleReplacementPlugin() 
  13.   ] 

HMR 中的 Server 和 Client

devServer 通知瀏覽器文件變更

通過翻閱 webpack-dev-server 源碼 在這一過程中,依賴于 sockjs 提供的服務端與瀏覽器端之間的橋梁,在 devServer 啟動的同時,建立了一個 webSocket 長鏈接,用于通知瀏覽器在 webpack 編譯和打包下的各個狀態,同時監聽 compile 下的 done 事件,當 compile 完成以后,通過 sendStats 方法, 將重新編譯打包好的新模塊 hash 值發送給瀏覽器。

  1. // webpack-dev-server/blob/master/lib/Server.js 
  2. sendStats(sockets, stats, force) { 
  3.     const shouldEmit = 
  4.       !force && 
  5.       stats && 
  6.       (!stats.errors || stats.errors.length === 0) && 
  7.       (!stats.warnings || stats.warnings.length === 0) && 
  8.       stats.assets && 
  9.       stats.assets.every((asset) => !asset.emitted); 
  10.  
  11.     if (shouldEmit) { 
  12.       this.sockWrite(sockets, 'still-ok'); 
  13.  
  14.       return
  15.     } 
  16.  
  17.     this.sockWrite(sockets, 'hash', stats.hash); 
  18.  
  19.     if (stats.errors.length > 0) { 
  20.       this.sockWrite(sockets, 'errors', stats.errors); 
  21.     } else if (stats.warnings.length > 0) { 
  22.       this.sockWrite(sockets, 'warnings', stats.warnings); 
  23.     } else { 
  24.       this.sockWrite(sockets, 'ok'); 
  25.     } 
  26.   } 

Client 接收到服務端消息做出響應

webpack-dev-server/client 當接收到 type 為 hash 消息后會將 hash 值暫時緩存起來,同時當接收到到 type 為 ok 的時候,對瀏覽器執行 reload 操作。

reload 策略選擇

  1. function reloadApp( 
  2.   { hotReload, hot, liveReload }, 
  3.   { isUnloading, currentHash } 
  4. ) { 
  5.   if (isUnloading || !hotReload) { 
  6.     return
  7.   } 
  8.  
  9.   if (hot) { 
  10.     log.info('App hot update...'); 
  11.  
  12.     const hotEmitter = require('webpack/hot/emitter'); 
  13.  
  14.     hotEmitter.emit('webpackHotUpdate', currentHash); 
  15.  
  16.     if (typeof self !== 'undefined' && self.window) { 
  17.       // broadcast update to window 
  18.       self.postMessage(`webpackHotUpdate${currentHash}`, '*'); 
  19.     } 
  20.   } 
  21.   // allow refreshing the page only if liveReload isn't disabled 
  22.   else if (liveReload) { 
  23.     let rootWindow = self; 
  24.  
  25.     // use parent window for reload (in case we're in an iframe with no valid src) 
  26.     const intervalId = self.setInterval(() => { 
  27.       if (rootWindow.location.protocol !== 'about:') { 
  28.         // reload immediately if protocol is valid 
  29.         applyReload(rootWindow, intervalId); 
  30.       } else { 
  31.         rootWindow = rootWindow.parent; 
  32.  
  33.         if (rootWindow.parent === rootWindow) { 
  34.           // if parent equals current window we've reached the root which would continue forever, so trigger a reload anyways 
  35.           applyReload(rootWindow, intervalId); 
  36.         } 
  37.       } 
  38.     }); 
  39.   } 
  40.  
  41.   function applyReload(rootWindow, intervalId) { 
  42.     clearInterval(intervalId); 
  43.  
  44.     log.info('App updated. Reloading...'); 
  45.  
  46.     rootWindow.location.reload(); 
  47.   } 

通過翻閱 webpack-dev-server/client源碼,我們可以看到,首先會根據 hot 配置決定是采用哪種更新策略,刷新瀏覽器或者代碼進行熱更新(HMR),如果配置了 HMR,就調用 webpack/hot/emitter 將最新 hash 值發送給 webpack,如果沒有配置模塊熱更新,就直接調用 applyReload下的location.reload 方法刷新頁面。

webpack 根據 hash 請求最新模塊代碼

在這一步,其實是 webpack 中三個模塊(三個文件,后面英文名對應文件路徑)之間配合的結果,首先是 webpack/hot/dev-server(以下簡稱 dev-server) 監聽第三步 webpack-dev-server/client 發送的 webpackHotUpdate 消息,調用 webpack/lib/HotModuleReplacement.runtime(簡稱 HMR runtime)中的 check 方法,檢測是否有新的更新,在 check 過程中會利用 webpack/lib/JsonpMainTemplate.runtime(簡稱 jsonp runtime)中的兩個方法 hotDownloadUpdateChunk 和 hotDownloadManifest , 第二個方法是調用 AJAX 向服務端請求是否有更新的文件,如果有將發更新的文件列表返回瀏覽器端,而第一個方法是通過 jsonp 請求最新的模塊代碼,然后將代碼返回給 HMR runtime,HMR runtime 會根據返回的新模塊代碼做進一步處理,可能是刷新頁面,也可能是對模塊進行熱更新。

在這個過程中,其實是 webpack 三個模塊配合執行之后獲取的結果

webpack/hot/dev-server監聽 client 發送的webpackHotUpdate消息

  1. // .... 
  2. var hotEmitter = require("./emitter"); 
  3.  hotEmitter.on("webpackHotUpdate"function (currentHash) { 
  4.   lastHash = currentHash; 
  5.   if (!upToDate() && module.hot.status() === "idle") { 
  6.    log("info""[HMR] Checking for updates on the server..."); 
  7.    check(); 
  8.   } 
  9.  }); 
  10.  log("info""[HMR] Waiting for update signal from WDS..."); 
  11. else { 
  12.  throw new Error("[HMR] Hot Module Replacement is disabled."); 

[HMR runtime/check()](https://github.com/webpack/webpack/blob/v4.41.5/lib/HotModuleReplacement.runtime.js)檢測是否有新的更新,check 過程中會利用webpack/lib/web/JsonpMainTemplate.runtime.js中的hotDownloadUpdateChunk(通過 jsonp 請求新的模塊代碼并且返回給 HMR Runtime)以及hotDownloadManifest(發送 AJAx 請求向 Server 請求是否有更新的文件,如果有則會將新的文件返回給瀏覽器)

獲取更新文件列表

獲取模塊更新以后的最新代碼

HMR Runtime 對模塊進行熱更新

這里就是整個 HMR 最關鍵的步驟了,而其中 最關鍵的 無非就是hotApply這個方法了,由于代碼量實在太多,這里我們直接進入過程解析(關鍵代碼),有興趣的同學可以閱讀一下源碼。

找出 outdatedModules 和 outdatedDependencies

刪除過期的模塊以及對應依賴

  1. // remove module from cache 
  2. delete installedModules[moduleId]; 
  3.  
  4. // when disposing there is no need to call dispose handler 
  5. delete outdatedDependencies[moduleId]; 

新模塊添加至 modules 中

  1. for(moduleId in appliedUpdate) { 
  2.   if(Object.prototype.hasOwnProperty.call(appliedUpdate, moduleId)) { 
  3.       modules[moduleId] = appliedUpdate[moduleId]; 
  4.   } 

至此 一整個模塊替換的流程已經結束了,已經可以獲取到最新的模塊代碼了,接下來就輪到業務代碼如何知曉模塊已經發生了變化~

HMR 中的 hot 成員

HotModuleReplaceMentPlugin

由于我們編寫的 JavaScript 代碼是沒有任何規律可言的模塊,可以導出的是一個模塊、函數、甚至于只是一個字符串 而對于這些毫無規律可言的模塊來說 Webpack 是無法提供一個通用的模塊替換方案去處理的 因此在這種情況下,還想要體驗完整的 HMR 開發流程 是需要我們自己手動處理 當 JS 模塊更新以后,如何將更新以后的 JS 模塊替換至頁面當中 因此 HotModuleReplacementPlugin 為我們提供了一系列關于 HMR 的 API 而其中 最關鍵的部分則是hot.accept。

接下來 我們將嘗試 自己手動處理 JS 模塊更新 并通知到瀏覽器實現對應的局部刷新

:::info 當前主流開發框架 Vue、React 都提供了統一的模塊替換函數, 因此 Vue、React 項目并不需要針對 HMR 做手動的代碼處理,同時 css 文件也由 style-loader 統一處理 因此也不需要額外的處理,因此接下去的代碼處理邏輯,全部建立在純原生開發的基礎之上實現 :::

回到代碼中來 假設當前 main.js 文件如下

  1. // ./src/main.js 
  2. import createChild from './child' 
  3.  
  4. const child = createChild() 
  5. document.body.appendChild(child) 

main.js 是 Webpack 打包的入口文件 在文件中引入了 Child 模塊 因此 當 Child 模塊里的業務代碼更改以后 webpack 必然會重新打包,并且重新使用這些更新以后的模塊,所以,我們需要在 main.js 里實現去處理它所依賴的這些模塊更新后的熱替換邏輯

在 HMR 已開啟的情況下,我們可以通過訪問全局的module對象下的hot 成員它提供了一個accept 方法,這個方法用來注冊當某個模塊更新以后需要如何處理,它接受兩個參數 一個是需要監聽模塊的 path(相對路徑),第二個參數就是當模塊更新以后如何處理 其實也就是一個回調函數

  1. // main.js 
  2. // 監聽 child 模塊變化 
  3. module.hot.accept('./child', () => { 
  4.   console.log('老板好,child 模塊更新啦~'
  5. }) 

當做完這些以后,重新運行 npm run serve 同時修改 child 模塊 你會發現,控制臺會輸出以上的 console 內容,同時,瀏覽器也不會自動更新了,因此,我們可以得出一個結論 當你手動處理了某個模塊的更新以后,是不會出發自動刷新機制的,接下來 就來一起看看 其中的原理 以及 如何實現 HMR 中的 JS 模塊替換邏輯

module.hot.accept 原理

為什么我們只有調用了moudule.hot.accept才可以實現熱更新, 翻看源碼 其實可以發現實現如下

  1. // 部分源碼 
  2. accept: function (dep, callback, errorHandler) { 
  3.     if (dep === undefined) hot._selfAccepted = true
  4.     else if (typeof dep === "function") hot._selfAccepted = dep; 
  5.     else if (typeof dep === "object" && dep !== null) { 
  6.      for (var i = 0; i < dep.length; i++) { 
  7.       hot._acceptedDependencies[dep[i]] = callback || function () {}; 
  8.       hot._acceptedErrorHandlers[dep[i]] = errorHandler; 
  9.      } 
  10.     } else { 
  11.      hot._acceptedDependencies[dep] = callback || function () {}; 
  12.      hot._acceptedErrorHandlers[dep] = errorHandler; 
  13.     } 
  14.    }, 
  1. // module.hot.accept 其實等價于 module.hot._acceptedDependencies('./child) = render 
  2. // 業務邏輯實現 
  3. module.hot.accept('./child', () => { 
  4.   console.log('老板好,child 模塊更新啦~'
  5. }) 

accept 往hot._acceptedDependencies這個對象里存入局部更新的 callback, 當模塊改變時,對模塊需要做的變更,搜集到_acceptedDependencies中,同時當被監聽的模塊內容發生了改變以后,父模塊可以通過_acceptedDependencies知道哪些內容發生了變化。

實現 JS 模塊替換

當了解了 accpet 方法以后,其實我們要考慮的事情就非常簡單了,也就是如何實現 cb 里的業務邏輯,其實當 accept 方法執行了以后,在其回調里是可以獲取到最新的被修改了以后的模塊的函數內容的

  1. // ./src/main.js 
  2. import createChild from './child' 
  3.  
  4. console.log(createChild) // 未更新前的函數內容 
  5. module.hot.accept('./child', ()=> { 
  6.  console.log(createChild) // 此時已經可以獲取更新以后的函數內容 
  7. }) 

既然是可以獲取到最新的函數內容 其實也就很簡單了 我們只需要移除之前的 dom 節點 并替換為最新的 dom 節點即可,同時我們也需要記錄節點里的內容狀態,當節點替換為最新的節點以后,追加更新原本的內容狀態

  1. // ./src/main.js 
  2. import createChild from './child' 
  3.  
  4. const child = createChild() 
  5. document.body.appendChild(child) 
  6.  
  7. // 這里需要額外注意的是,child 變量每一次都會被移除,所以其實我們一個記錄一下每次被修改前的 child 
  8. let lastChild = child 
  9. module.hot.accept('./child', ()=> { 
  10.   // 記錄狀態 
  11.   const value = lastChild.innerHTML 
  12.   // 刪除節點 
  13.  document.body.remove(child) 
  14.   // 創建最新節點 
  15.   lastChild = createChild() 
  16.   // 恢復狀態 
  17.   lastChild.innerHTMl = value 
  18.   // 追加內容 
  19.   document.body.appendChild(lastChild) 
  20. }) 

到這里為止,對于如何手動實現一個 child 模塊的熱更新替換邏輯已經全部實現完畢了,有興趣的同學可以自己也手動實現一下~

:::tips tips: 手動處理 HMR 邏輯過程中 如果 HMR 過程中出現報錯 導致的 HRM 失效,其實只需要在配置文件中將hot: true 修改為 hotOnly: true即可 :::

寫在最后

 

希望通過這篇文章,能夠幫助到大家加深對 HMR 的理解,同時解決一下開發場景會遇到的問題(例如 脫離框架自己實現模塊熱更新),

 

責任編輯:武曉燕 來源: 微醫大前端技術
相關推薦

2024-04-26 08:41:04

ViteHMR項目

2021-09-13 09:40:35

Webpack 前端HMR 原理

2020-07-08 14:50:18

WebpackHMR前端

2021-09-09 06:55:43

Web剪輯視頻

2022-03-24 13:36:18

Java悲觀鎖樂觀鎖

2023-05-09 08:25:26

Gaussdb數據庫開源數據庫

2010-05-06 09:50:16

負載均衡產品

2019-06-05 15:00:28

Java代碼區塊鏈

2018-07-25 13:34:14

Python微信撤回

2019-08-15 10:17:16

Webpack運行瀏覽器

2010-03-15 10:05:03

無線多連接

2014-06-17 09:51:57

Docker

2021-05-21 06:13:35

React Hooks react-refrReact

2021-12-20 00:03:38

Webpack運行機制

2024-07-18 00:05:58

Vite代碼前端

2021-12-19 07:21:48

Webpack 前端插件機制

2014-07-22 10:56:45

互聯網印度

2020-10-23 09:35:41

開源 Java 代碼

2023-11-01 13:48:00

反射java

2018-10-16 16:00:39

數據庫鎖舞MySQL
點贊
收藏

51CTO技術棧公眾號

久久精品国产亚洲av无码娇色 | 超碰在线播放91| 头脑特工队2在线播放| 香蕉久久夜色精品| 一本久久综合亚洲鲁鲁| 男人操女人下面视频| 日韩伦理精品| 自拍偷拍欧美激情| 蜜桃成人在线| 亚洲国产999| 美女在线视频一区| 国内精品视频在线| 国产67194| 久久99国产成人小视频| 日韩视频免费观看高清完整版在线观看 | 成年人网站免费在线观看| 精品国产黄a∨片高清在线| 一区二区三区在线高清| 一区二区国产精品视频| 夜夜嗨av一区二区三区免费区| 中文字幕第80页| sm在线播放| 中文字幕视频一区| 欧美日韩精品一区| 欧美 日韩 综合| 精品一区二区三区的国产在线播放| 91sa在线看| 久青草免费视频| 欧美第一精品| 亚洲视频一区二区三区| 国产麻豆剧传媒精品国产av| aa亚洲一区一区三区| 欧美亚洲精品一区| 日本少妇高潮喷水视频| 国产偷倩在线播放| 亚洲视频网在线直播| 日韩精品一区二区三区四区五区 | 日韩av在线电影网| 可以看的av网址| 高清久久一区| 欧美日本一区二区在线观看| 国产精品69页| 欧美理论影院| 欧美性xxxxx极品娇小| 亚洲中文字幕无码av永久| 影音先锋男人资源在线| 中文字幕一区二区三区不卡| 视频一区视频二区视频| 国产午夜在线视频| 91在线码无精品| 精品一区国产| 四虎在线免费观看| 91在线精品一区二区| 国模精品一区二区三区| 神马久久久久久久久久| 成人91在线观看| 国产一区国产精品| 天天干天天爱天天操| 99久久国产免费看| 久久精品国产第一区二区三区最新章节 | 国产精品suv一区二区69| 欧美另类综合| 欧美黑人极品猛少妇色xxxxx| 欧美成人黄色网| 国产一区二区三区四区老人| 久久久久久久久久久av| 在线免费观看毛片| 亚洲女人av| 国产精品第二页| 一级片视频播放| 国产资源在线一区| 国产精品国产精品国产专区不卡| 少妇高潮久久久| 久久精品夜夜夜夜久久| 香蕉久久夜色| 久草中文在线| 亚洲无人区一区| 日本黄色三级大片| 激情欧美一区二区三区黑长吊| 欧美日韩一级片网站| 天天av天天操| 一呦二呦三呦国产精品| 中文字幕亚洲一区二区三区五十路 | 蜜桃a∨噜噜一区二区三区| 伊人久久五月天| 国产麻豆视频在线观看| 亚洲激情黄色| 国产精品久久久久一区二区| 99热这里只有精品5| 99久久99久久久精品齐齐| 日本三级中国三级99人妇网站| 日本在线免费看| 亚洲风情在线资源站| 国产性生交xxxxx免费| 精品国产三区在线| 日韩禁在线播放| 老司机成人免费视频| 亚洲黄色免费| 91精品国产自产在线| 高潮一区二区三区乱码| 国产蜜臀97一区二区三区 | 精品无码人妻一区二区免费蜜桃| 中文字幕日韩欧美精品高清在线| 欧美一区第一页| 国产三区在线播放| 久久久亚洲国产美女国产盗摄| 国产经典久久久| 亚洲wwww| 亚洲精品国产拍免费91在线| 黄色一级大片在线免费观看| 老鸭窝毛片一区二区三区| 亚洲一区亚洲二区| 国产高清免费在线播放| 亚洲第一福利一区| 小早川怜子一区二区三区| 最新国产一区| 91国自产精品中文字幕亚洲| www.国产黄色| 亚洲国产激情av| 免费看又黄又无码的网站| 国产精品美女久久久久| 最近2019中文字幕mv免费看| 国产免费一级视频| 99久久久久久| 国产一级片91| 国产亚洲观看| 日韩专区在线观看| 欧美成人精品网站| 91香蕉国产在线观看软件| 日本一区午夜艳熟免费| 日韩精品一区二区三区中文| 日韩最新av在线| 中文字幕人妻一区二区在线视频| 久久久久久免费| 久久久999免费视频| 97视频一区| 欧美日韩成人在线视频| 国产熟女一区二区丰满| 最新日韩av在线| 中文字幕22页| 精品毛片免费观看| 国产激情综合五月久久| 青青草在线免费视频| 精品久久久久久久久久久久| 制服丝袜在线第一页| 红桃视频国产精品| 国产精华一区二区三区| 国产区美女在线| 亚洲第一视频网| 色播视频在线播放| 99re亚洲国产精品| 无码人妻丰满熟妇区96| 亚洲精品播放| 国产国语videosex另类| 一区二区高清不卡| 欧美一区二区在线观看| 欧美成人777| 国产mv日韩mv欧美| 欧美人成在线观看| 玖玖玖免费嫩草在线影院一区| 久久久视频在线| 青春有你2免费观看完整版在线播放高清| 欧美日韩亚洲91| 性欧美丰满熟妇xxxx性仙踪林| 日韩精品成人一区二区在线| 亚洲黄色成人久久久| 91精品一区| 欧美疯狂xxxx大交乱88av| 亚洲欧美强伦一区二区| 欧美丝袜第一区| 成人性生交大片免费看无遮挡aⅴ| 麻豆精品国产传媒mv男同| 青青草影院在线观看| 国产91精品入| 国产福利视频一区二区| av在线播放国产| 日韩高清人体午夜| 日韩欧美一级大片| 一区二区三区视频在线看| 一级黄色免费视频| 久久久人人人| 中文字幕一区二区三区在线乱码| 亚洲精品一区二区三区在线| 91精品国产乱码久久久久久久久 | av不卡一区二区| 欧美最猛黑人xxxx黑人猛叫黄 | 欧美激情免费观看| 欧美在线一卡| 欧美军同video69gay| 久久精品国产亚洲av高清色欲| 久久久不卡影院| 奇米777在线| 久久精品五月| 女同性恋一区二区| 色爱av综合网| 91在线视频成人| 欧美大片高清| 欧美高清自拍一区| 成人免费在线电影| 欧美精品一区二区在线观看| 伊人久久一区二区| 精品日本高清在线播放| sm捆绑调教视频| 91视频com| 极品人妻一区二区| 日本成人中文字幕在线视频| 成人av在线不卡| 亚洲精品97| 日韩一区免费观看| 久久九九热re6这里有精品| 91精品啪aⅴ在线观看国产| 亚洲欧美小说色综合小说一区| 欧美精品日韩www.p站| 成人在线视频成人| 国产丝袜精品视频| 亚洲第一页综合| 91精品欧美福利在线观看| 亚洲第一网站在线观看| 五月天一区二区| 久久久久亚洲AV成人| 国产精品美日韩| 久久久久久国产免费a片| 26uuu精品一区二区在线观看| 久久久久无码国产精品一区李宗瑞| 毛片av一区二区三区| 精品少妇无遮挡毛片| 在线亚洲精品| 国产二区视频在线| 欧美日韩一区自拍| 日本女人高潮视频| 91麻豆国产自产在线观看亚洲 | 91啦中文在线| 亚洲香蕉伊综合在人在线视看| 天堂网www中文在线| 亚洲国产成人久久| 午夜影院在线视频| 亚洲第一网站免费视频| 亚洲国产精品无码久久| 精品欧美一区二区久久| www.97超碰| 日韩视频免费观看高清完整版在线观看| 91精品中文字幕| 欧美日韩成人激情| 91午夜交换视频| 3751色影院一区二区三区| 国产精品国产三级国产普通话对白| 欧美精品网站| 欧美sm极限捆绑bd| 又色又爽又黄无遮挡的免费视频| 在线观看亚洲一区| 欧美一级做a爰片免费视频| 欧美在线高清视频| 亚洲视频中文字幕在线观看| 欧美日韩高清影院| 国产三级视频在线播放| 精品久久久久久久一区二区蜜臀| 成人午夜精品福利免费| 亚洲韩国日本中文字幕| 欧美香蕉爽爽人人爽| 一本一道久久a久久精品逆3p | 欧美肥臀大乳一区二区免费视频| 18av在线播放| 韩国精品美女www爽爽爽视频| 日韩av一卡| 国产精品久久久久久一区二区 | 日韩一卡二卡在线观看| 亚洲人成精品久久久久| 超碰手机在线观看| 亚洲国产欧美日韩另类综合| 亚洲精品午夜国产va久久成人| 在线亚洲一区观看| 国产又粗又长又黄| 亚洲电影中文字幕| 精品视频二区| 久久久国产一区二区| av福利导福航大全在线| 国产精品电影一区| 国产一区二区三区黄网站| 久久久com| 日韩啪啪电影网| 国产一区二区三区乱码| 久久九九精品| 在线播放免费视频| 99精品视频一区二区三区| 欧美丰满美乳xxⅹ高潮www| 亚洲免费视频中文字幕| 秋霞精品一区二区三区| 欧美一区永久视频免费观看| 四虎在线免费观看| 久久久精品视频在线观看| 欧美日韩国产观看视频| 国产美女高潮久久白浆| 国产乱论精品| 一区二区不卡在线| 国产日韩欧美三区| 一级黄色录像在线观看| 99久精品国产| 538精品在线视频| 色哟哟国产精品| 亚洲国产av一区二区| 色偷偷亚洲男人天堂| 玖玖在线播放| 99r国产精品视频| 日本在线电影一区二区三区| 青青草国产精品视频| 黑人巨大精品欧美一区| 国产成人av一区二区三区不卡| 亚洲综合区在线| 一区二区三区免费在线视频| 亚洲精品自拍第一页| 搞黄网站在线看| 91精品久久久久久久久久入口| 久草成人资源| 青青草视频在线免费播放| 国产伦精品一区二区三区在线观看| 日韩人妻无码精品综合区| 亚洲高清免费在线| 国产精品永久久久久久久久久| 亚洲最新视频在线| 综合另类专区| 久久av二区| 亚洲高清在线| 四虎永久免费观看| 亚洲女同一区二区| 一级黄色录像大片| 伊人伊人伊人久久| 羞羞影院欧美| 奇米888一区二区三区| 国产日韩一区二区三区在线播放 | **欧美大码日韩| 亚洲一级黄色大片| 一区二区三区天堂av| 黄瓜视频成人app免费| 欧美日韩在线一二三| 亚洲一区二区三区高清不卡| 亚洲久久久久久| 亚洲高清视频的网址| 亚洲精品久久久蜜桃动漫 | 在线观看精品| 三区精品视频观看| 裸体一区二区| 久久成人激情视频| 欧美少妇性性性| 免费看美女视频在线网站| 成人动漫网站在线观看| 国产精品成久久久久| 可以看污的网站| 亚洲另类在线一区| 国产黄a三级三级看三级| 久久天天躁狠狠躁夜夜躁2014| 老司机亚洲精品一区二区| 五月天激情图片| 国产v日产∨综合v精品视频| 国产亚洲欧美精品久久久久久| 欧美成人免费网站| 国产精品xx| 欧美一级爽aaaaa大片| 日韩 欧美一区二区三区| 中文字幕第69页| 91精品在线麻豆| 激情网站在线| 久久综合入口| 免费观看成人鲁鲁鲁鲁鲁视频| 日韩欧美在线视频播放| 欧美成人欧美edvon| 天堂网在线最新版www中文网| 日本成人三级电影网站| 久久av老司机精品网站导航| 国产av无码专区亚洲av毛网站| 精品福利一区二区三区免费视频| 日本а中文在线天堂| 亚洲日本理论电影| 国产99久久久国产精品潘金网站| 欧美福利视频一区二区| 亚洲色图偷窥自拍| 国产精品色婷婷在线观看| 免费av手机在线观看| 中文无字幕一区二区三区| 亚洲xxx在线| 国产精品2018| 亚洲欧美一级二级三级| 实拍女处破www免费看| 欧美一区二区三区啪啪| 午夜伦理福利在线| 中文字幕日韩精品久久| thepron国产精品| 中文字幕激情视频| 欧美激情奇米色| 欧美色图国产精品| 欧美一级片在线免费观看| 色综合色综合色综合| 最近中文字幕免费mv2018在线 | 国产在线视频网| 99在线视频播放| 日韩精品一级二级| 久久人人爽人人爽人人| 亚洲视频综合网| 久本草在线中文字幕亚洲| 蜜桃福利午夜精品一区| 91国模大尺度私拍在线视频|