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

大型前端項目的斷點調(diào)試共享化和復用化實踐

開發(fā) 開發(fā)工具
隨著我們項目越來越大,我們有可能需要維護很多的模塊,我們騰訊文檔 Excel 項目大模塊有 10 幾個,而每個大模塊分別有 N 個小模塊,每個大模塊下的小模塊都有主要的負責人在跟進模塊問題。

 [[345256]]

背景

隨著我們項目越來越大,我們有可能需要維護很多的模塊,我們騰訊文檔 Excel 項目大模塊有 10 幾個,而每個大模塊分別有 N 個小模塊,每個大模塊下的小模塊都有主要的負責人在跟進模塊問題。

 

這就會導致一個很大的問題是,模塊負責人大部分情況只會關注自己模塊的問題,而不甚了解其他負責人手上模塊的具體問題。

比如:當我們有用戶反饋使用復制粘貼有問題的時候,我們想要快速去定位這個問題,就只能找復制粘貼對應的模塊負責人處理,如果復制粘貼模塊負責人請假了,那么其他負責人去處理這個問題的時候,解決成本就會非常大,因為其他負責人可能根本對這個模塊不熟悉。

 

又比如:我們新來了幾個同學,想讓他快速去排查用戶反饋的問題的時候,我們只能手把手把我們該模塊調(diào)試的經(jīng)驗傳授他,和所熟知的各個坑點告訴他,或者整理好對應的 iwiki 給他看(一般效率低也沒人看!),讓他去慢慢定位問題,這樣的每個新同學對模塊的熟悉,學習和維護的成本就會變得越來越大,項目越大這種情況就會越嚴重!

 

所以我們思考了很多,該怎么去解決這些問題,至少要讓模塊維護成本變低,變得更好去維護和定位問題。

方案

由于上面的問題真的很痛,我們在爬滾中逐漸摸索了一套方案,我們暫且叫它為基于斷點調(diào)試的共享化和復用化的實踐方案吧,這里有個關鍵詞是斷點,相比作為每一個開發(fā)者都不陌生,在我們前端,模塊定位問題的時候,我們少不了去使用斷點去斷住一些代碼運行關鍵的地方。下面舉一個例子:

 

  1. class CopyPaste { 
  2.     // 內(nèi)部粘貼 
  3.     pasteFromInter(){ ...} 
  4.     // 外部粘貼 
  5.     pasteFromOuter(){ debugger; ...} 
  6.     // 外部圖文粘貼 
  7.     isShapePasteFromOuter(){ ... } 
  8.     // 外部圖片粘貼 
  9.     isImgPasteFromOuter(){ ... } 
  10.     // 外部文本粘貼 
  11.     isTextFromOuter(){ ... } 

上面這段代碼是當用戶反饋一個復制粘貼問題的時候,熟悉該模塊的負責人根據(jù)用戶的反饋,知道用戶是外部粘貼出現(xiàn)了問題,由于他對該模塊熟悉,他會快速的在瀏覽器的控制臺打斷點,或者手動在源代碼注入 debugger 關鍵詞去一步一步定位用戶的問題,他會先檢查內(nèi)部粘貼 pasteFromOuter 是否觸發(fā)了,然后檢查函數(shù) isShapePasteFromOuter 是否運行成功,出參和入?yún)⑹欠裾_,是否代碼走歪了,去了 isImgPasteFromOuter。

 

然后在問題排查修復完后,長舒一口氣,等遇到下一個問題的時候,再把瀏覽器或者代碼中當前的這些調(diào)試的痕跡清理干凈,再周而復始的重復上面的一系列動作,我相信大部分的同學每天排查問題甚至做需求都是重復著上面的類似動作,我們是否可以考慮一下把這些珍貴的調(diào)試痕跡給保存下來,等自己或者其他同學遇到類似模塊問題的時候,我們把這些凝聚著我們血與淚的心路歷程再自動復現(xiàn)一次?

代碼片段 記錄 debugger 位置
pasteFromInter 2 行 4 列
isShapePasteFromOuter 256 行 89 列
isImgPasteFromOuter 867 行 12 列

對于大型項目來說,每一個小 Bug 的調(diào)試鏈路的時間成本都是無比巨大的,也是難以復刻和重現(xiàn)的,我們能做的就是當再次遇到相似問題的時候,復用相似的調(diào)試經(jīng)驗。有過受傷的痕跡和經(jīng)歷,當問題再次相遇,我們應該會更自信和從容。

所以我們首要任務其實就變成了是保留珍貴的調(diào)試鏈路,也就是保留無數(shù)個日夜,那些深扎并刺痛我們內(nèi)心深處的每個斷點。

 

插件化

在實踐的過程中我們嘗試過無數(shù)的方法,第一個方案就是基于瀏覽器插件,實現(xiàn)斷點留存,基于谷歌瀏覽器插件開發(fā)提供的接口 chrome.debugger,它是 Chrome 遠程調(diào)試協(xié)議的一種消息傳輸方式。chrome.debugger 可以附加到一個或多個標簽頁調(diào)試 JavaScript。并使用調(diào)試對象基于 sendCommand 和 onEvent 來做插件通信。它可以讓我們在插件去調(diào)試頁面,很多插件和工具是基于這個協(xié)議來跟瀏覽器的控制臺去做通信,這種方案現(xiàn)只能實現(xiàn)一個遠程的調(diào)試面板,這個面板類似瀏覽器本身的調(diào)試界面可以加載代碼然后記錄斷點,最后可以把這些斷點分享出去。

這種方案體驗會比較糟糕,首先插件自己實現(xiàn)的調(diào)試面板無法像谷歌瀏覽器那么好的體驗,其次是插件需要開發(fā)主動去安裝,分享的前提是雙方都需要安裝好對應的插件,開發(fā)和推廣成本都比較高,所以個人不是很建議,但是這不代表這個方案走不通,因為這個基于插件還可以有另外一種實現(xiàn),就是下面的 debug 函數(shù)方案。

debug 函數(shù)

具體是利用函數(shù)斷點 debug(functionName) 和 undebug(functionName) 方法,其中 functionName 是要調(diào)試的函數(shù)。我們可以將 debug() 插入到的代碼中(這個方法和 console.log() 語句相似),也可以從 DevTools 控制臺中進行調(diào)用。debug() 相當于在第一行函數(shù)中設置代碼行斷點。

 

一般情況是在控制臺中使用,這個方法配合插件會有比較好的體驗,因為插件使用 chrome.devtools.inspectedWindow.eval 方法配合瀏覽器的接口可以把代碼注入到控制臺中執(zhí)行,從而實現(xiàn)幫你自動下發(fā)斷點的功能。

 

  1. chrome.devtools.inspectedWindow.eval( 
  2.   `debug(window.xxxApi);`, 
  3.   (value) => { 
  4.     callback && callback(value); 
  5.   } 
  6. ); 

 

但是細心的同學發(fā)現(xiàn)我使用 debug 函數(shù)監(jiān)聽的是一個全局的函數(shù) window.xxxApi,所以這里也總結一下經(jīng)驗,這個方法的缺陷就是如果你在控制臺使用,它會在你的上下文尋找該函數(shù),所以它一般只能用于全局的函數(shù)打點,如果需要打點的函數(shù)不在上下文,還需要手動斷點到目標函數(shù)的范圍,然后使用函數(shù)打點來觸發(fā),如果是閉包函數(shù)那就毫無辦法了,但是瑕不掩瑜,這個方法能幫我們快速定位任何的全局函數(shù),就算代碼被混淆了,它還是能快讀把函數(shù)斷點給你加上,所以這個方案我建議可以作為一個備選方案,在某些情況下能發(fā)揮奇效!

AST 注入

經(jīng)歷過上面的各種坑之后,下面我們簡單介紹我們實現(xiàn)的一套方案吧:

我們的方案其實是在之前函數(shù)調(diào)用鏈方案基礎上做的一種改進,既然我們開發(fā)可以自己在代碼中輸入 debugger 關鍵詞去斷住任何地方的代碼,我們何不把這個工作交給工具?

 

首先我們可以用使用狀態(tài)機去告訴工具我們需要分發(fā)的打點的位置在哪里,類似我們常用 whistle 的配置表:

 

  1. Module 'CopyPaste' 
  2.     index.ts -f pasteFromInter -s !(()=>{ console.log(window.Worker) })() 
  3.     index.ts -f pasteFromOuter -s console.log('success') -check messagecenter1 
  4.     index.ts -f isShapePasteFromOuter 
  5. End Module 
  • Module <-- state --> End Module 這里描述一個狀態(tài),是一個分發(fā)斷點的行為,用來需要監(jiān)聽那類模塊的,例如:復制粘貼模,數(shù)據(jù)層模塊還是數(shù)據(jù)層模塊
  • -f functionname -s code 這里可以描述該狀態(tài)的具體行為特征,例如:在 pasteFromInter 函數(shù)中分發(fā)斷點,并注入 debugger 代碼。

在 webpack 中我們可以在 loader 或者 plugin 這兩個過程中去解析這份配置文件,這里你也可以使用第三方庫或者正則來解析上面這些狀態(tài)文本。我是在 loader 中去解析這份狀態(tài)表的,我在全局目錄下或者局部模塊內(nèi)定義一份 .debug.json 來寫入上述的狀態(tài),然后解析出一份 map 對象出來:

 

  1. args = argument({ 
  2.     "--class": String, // 類 
  3.     "--function": String, // 函數(shù) 
  4.     "--code": String, // 函數(shù) 
  5.     "-c""--class", // 轉(zhuǎn)義替換 
  6.     "-f""--function"
  7.     "-s""--code"
  8.   },{ argv: debugConfigValue, } 
  9. ); 

如果不想用狀態(tài)機的方式去寫配置文件的話,其實也可以使用一份 debug.json 文件來描述斷點的位置,這種方式更簡單,解析 json 文件的成本比狀態(tài)機的配置文件低不少,json 文件在這里涉及的主要字段分別是需要檢測代碼的路徑,這個方便工具去定位文件,然后是需要檢測的類或者函數(shù)的名字,這個方便工具去定位代碼的位置,還有檢測項的名字和需要檢測的代碼,和一個關鍵的鍵值:

 

  1.   "MessageCenter": { 
  2.     "function": [ 
  3.       { 
  4.         "path""src/core/network/message-center/SendMessageCenter.ts"
  5.         "name""_sendUserChanges"
  6.         "title""數(shù)據(jù)層斷點測試2"
  7.         "code""__console.log('數(shù)據(jù)層斷點測試2')"
  8.         "key""MessageCenter|function|1" 
  9.       } 
  10.     ] 
  11.   } 

這里鍵值的涉及可以定義的清晰點,比如 MessageCenter|function|1 指的是對 MessageCenter 模塊的文件里面的某一個函數(shù)打點,以后還可以繼續(xù)改進這樣寫 MessageCenter|class|1:12,意思是 MessageCenter 模塊的文件里面某一個類的具體位置打點,如果這個 key 的語義越豐富,后續(xù)分發(fā)的打點也會更精確,定位問題也會更高效,具體這個可以根據(jù)業(yè)務場景去定義。

 

  1. class CopyPaste { 
  2.     // 內(nèi)部粘貼 
  3.     pasteFromInter(){ 
  4.         debugger 
  5.         ... 
  6.     } 

當我們有了配置文件,我們就得思考怎么無入侵的在代碼里面加入調(diào)試和檢測代碼了,我們首選通過 AST 去注入,它可以幫我們把代碼關鍵部分給梳理成一顆樹出來,比如抹掉冒號、括號、分號等,能讓我們把精力放在重要的節(jié)點上,上面的代碼經(jīng)過解析會得到下面這棵 AST 語法樹:

 

  1.   "program": { 
  2.     "type""Program"
  3.     "body": [{ 
  4.       "type""ClassDeclaration"
  5.       "id": {{ "type""Identifier""identifierName""CopyPaste" }, "name""CopyPaste" }, 
  6.       "body": { 
  7.         "type""ClassBody"
  8.         "body": [{ 
  9.             "type""ClassMethod"
  10.             "key": { "type""Identifier""name""pasteFromInter" }, 
  11.             "body": { "type""BlockStatement""body": [{ "type""DebuggerStatement" }]}, 
  12.             "leadingComments": [{ "type""CommentLine""value"" 內(nèi)部粘貼" }], 
  13.         }] 
  14.       } 
  15.     }] 
  16.   } 

而具體步驟大概如下:解析 MessageCenter|function|1 這段參數(shù)配置的字符串,得到函數(shù)名,模塊名,位置信息等,然后對代碼進行掃描并進行詞法和語法分析,并得到 AST 語法樹,根據(jù)剛才解析得到的函數(shù)名,模塊名,位置信息來匹配 AST 樹節(jié)點,在上面進行加入我們的調(diào)試和檢測代碼,最后再輸出經(jīng)過我們加工的代碼。

那上面這個原理我們都懂,具體怎么實現(xiàn)呢,我們可以在 webpack 工具使用 plugins 來實現(xiàn),在 plugins 中我們經(jīng)常會用到訪問者模式,就是說在訪問到某一個路徑的時候進行匹配,然后在對這個節(jié)點進行修改,比如上面這個 pasteFromInter 函數(shù),它是一個 ClassMethod,plugins 就會對代碼生成的 AST 樹進行訪問,訪問者可以匹配任何對應的詞法特性,我們就可以在這里匹配所有的 ClassMethod 然后根據(jù)路徑去拿到節(jié)點對應的信息,比如函數(shù)名,函數(shù)參數(shù)和函數(shù)位置等,拿到這些關鍵的信息,我們就可以對這個函數(shù)節(jié)點進行加工,也就是注入我們的調(diào)試和檢測代碼或者直接注入一個 debugger 去打斷點。

 

  1. plugins = { 
  2.   // 訪問器 
  3.   Visitor = { 
  4.       'ClassMethod'(path) { 
  5.         // 檢點 
  6.         path.node 
  7.       } 
  8.   } 

當然注入檢測代碼也是需要構造成 ClassMethod 的類似結構,所有我們可以配合 @babel/types 工具去快速注入一段代碼,比如最簡單的是注入一個 debugger:

 

  1. types.expressionStatement(types.identifier(`debugger`)) 

這樣就會在你匹配的路徑的特定位置放入一個 debugger,而你的代碼源文件本身其實是沒有任何改動的,只是通過 AST 樹配合配置文件成功融合了一段代碼到指定的位置,當然實際情況會比預想中的復雜,因為有可能下發(fā)的位置不是函數(shù)中的某個位置,可能是類函數(shù)中的某個位置,閉包函數(shù)中的某個位置,所以要兼容各種的語法結構,需要在 AST 中匹配這些函數(shù)的所有特征才能準確無誤的下發(fā)代碼,還是以函數(shù)作為例子,列出部分需要考慮的情況:

  • FunctionExpression

需要滿足到這兩種寫法,不然 debugger 會下發(fā)錯位置。

 

  1. this.xxx = function() { debugger } 
  2. const xxx = function() { debugger } 
  • ClassMethod

這個一般情況按下面的方式就能定位到了,但是如果要更精確比如是私有函數(shù)等,那就需要寫更精確的訪問器了。

 

  1. class xxx { xxx:(){ debugger } } 
  • FunctionDeclaration

除了要處理上面函數(shù)表達式的寫法,不要忘了函數(shù)還有聲明定義的寫法,所以這個也得滿上。

 

  1. function xxx() { debugger } 
  • ArrowFunctionExpression

最后還要考慮下箭頭函數(shù)的寫法

 

  1. const xxx = () => { debugger } 
  2. this.xxx = () => { debugger } 
  3. class xxx { xxx = () => { debugger } } 

雖然大部分情況匹配函數(shù)對項目下發(fā)的調(diào)試代碼能覆蓋大部分的場景,但總會有漏網(wǎng)之魚,比如有的同學想在類定義之前注入檢測代碼,那就需要繼續(xù)寫對應的訪問器去獲取路徑,然后對該位置去分發(fā)對應的檢測代碼,所以需要對各種語法和對應的訪問器類型很熟悉才能順利實現(xiàn)。

經(jīng)過上面的改造,我們會在最終代碼中會得到新代碼(已注入了所有檢測代碼),但是這樣會引發(fā)一個新的,當我們運行這份新代碼,我們上面所有的檢測代碼都會跑一遍,這樣就會斷住很多別的模塊負責人不想斷住的代碼區(qū)域,所以實際情況我們需要分發(fā)一個帶開關的檢測代碼,當然這個開關的涉及其實可以很簡單,如下:

 

  1. // 基于 AST 在模塊中分發(fā)的調(diào)試開關 
  2. if(require('@tencent/vdebugger').call(this, key)){ debugger } 
  3. // 或者這樣,雖然好看點,但這樣 debugger 在閉包里面拿不到上下文 
  4. require('@tencent/vdebugger').call(this, key) || (() => { debugger })() 
  5. // 注意這種下面類似這種寫法是不行的↓ 
  6. require('@tencent/vdebugger') || debugger 

我們可以使用 require('@tencent/vdebugger') 打包一個函數(shù),這個函數(shù)可以設計為在全局變量或者 localstorage 等地方讀取配置,然后返回一個布爾值,用于判斷是否執(zhí)行該位置的 debugger,這里為了調(diào)試方便有幾個小細節(jié)需要注意,debugger 這個關鍵詞自己要獨立一個作用域,所以你不能寫成類似這個樣子 false || debugger,還有 require('@tencent/vdebugger') 這個函數(shù)里面在讀取配置之后里面可以包一個 eval 方法來執(zhí)行檢測代碼,所以可以用 call 把當前作用域代理過來,更方便去做調(diào)試。

當然實際情況可能還要比想象中復雜,舉個簡單的例子:因為分發(fā)的開關有可能會注入到一些被打包到 worker 的代碼里面,worker 在大型項目中運用的很多,但是 worker 里面無法讀取 document、window 這些對象,雖然可以使用 navigator,location 和 XMLHttpRequest 等對象,但無法通過 localstorage 讀取配置等手段去控制調(diào)試開關了,所以你需要考慮一下是否需要讓調(diào)試開關分發(fā)到 worker 代碼中,如果分發(fā)了又要怎么去通信對應的開關等問題。

最簡單粗暴就是打包 worker 代碼的時候進行過濾。

 

  1. !isWorker && new DebuggerPlugin({ 
  2.     debugConfig: path.resolve(dirName, '../debug.json'), 
  3. }), 

當然如果需要分發(fā)的開關在 worker 中生效,就需要去實現(xiàn)一個讀取開關配置的通信手段,最常見的就是基于 postMessage 的通信手段,讓 require('@tencent/vdebugger') 函數(shù),即開關模塊接受主線程的配置去向 worker 的運行代碼下達是否執(zhí)行檢測代碼和啟動斷點的命令。

 

  1. myWorker.postMessage(xx); 
  2. myWorker.onmessage = () => { 
  3.   console.log('Message received from worker'); 

思考

實現(xiàn)了上面的基本功能之后,我們還可以繼續(xù)優(yōu)化很多體驗,比如我們還可以使用 webpack 的 plugin 來實現(xiàn)本地編譯時候的增量更新,這就能做到當我們更改本地配置文件的時候,自動分發(fā)斷點和調(diào)試代碼,邏輯也是比較簡單的,在 plugin 的 apply 周期使用內(nèi)置的庫 chokidar 去監(jiān)聽配置文件的變更,然后觸發(fā)編譯,重新走 AST 去編譯生成帶調(diào)試代碼合斷點的代碼:

 

  1. const chokidar = require('chokidar'); 
  2. this.watcher = chokidar.watch(["../src/**/.debug.json"], { 
  3.   usePolling: true
  4.   ignored: this.options.ignored 
  5. }); 

總結

關于這方面的調(diào)試相關文章不多,一路走來跳了不少的坑,感謝團隊成員的支持,并讓這個方案最終成功落地,也希望有更多志同道合的人加入我們騰訊文檔團隊,一起去探索和遨游,最后也希望這篇文章能給到你們一些啟發(fā)吧 。

【本文為51CTO專欄作者“騰訊技術工程”原創(chuàng)稿件,轉(zhuǎn)載請聯(lián)系原作者(微信號:Tencent_TEG)】

戳這里,看該作者更多好文

責任編輯:武曉燕 來源: 51CTO專欄
相關推薦

2022-10-09 14:50:24

前端pnpm工具

2023-09-07 20:04:06

前后端趨勢Node.js

2021-09-27 10:48:42

開發(fā)技能代碼

2021-09-27 09:04:40

Vue.js代碼庫開發(fā)人員

2020-09-22 12:20:23

前端架構插件

2022-05-09 09:28:04

Vite前端開發(fā)

2024-02-21 09:32:18

開發(fā)架構

2023-04-07 15:12:46

ReactReact-Intl

2024-12-26 08:00:38

2023-03-07 08:30:09

MCube模板緩存

2022-08-10 09:52:16

平臺實踐

2015-12-08 09:13:05

開發(fā)維護Java項目

2022-08-10 10:32:47

編程實踐

2021-01-25 10:30:52

數(shù)字化分析轉(zhuǎn)型首席執(zhí)行官

2018-10-29 12:21:21

源碼前端項目

2023-06-03 08:06:20

項目開發(fā)客戶端

2010-08-02 08:54:53

Flex模塊化

2018-06-12 15:55:44

數(shù)字化項目

2021-06-29 10:01:56

物聯(lián)網(wǎng)項目eSIM物聯(lián)網(wǎng)

2013-11-27 11:34:43

自動化部署Python
點贊
收藏

51CTO技術棧公眾號

亚洲一区二区影视| 5858s免费视频成人| 亚洲精品日韩欧美| 在线观看福利一区| 97久久久久久久| 国产麻豆精品| 日韩成人午夜电影| 精品999在线播放| 亚洲永久一区二区三区在线| 亚洲va在线观看| 久久久久久久久久久久久久久久久久久久| 久久理论电影网| 欧美夫妻性视频| 精品亚洲一区二区三区四区| 色综合久久网女同蕾丝边| 国产精品亚洲综合在线观看| 一区二区在线电影| 成人a视频在线观看| 久久久久久国产精品无码| 国产传媒在线观看| av在线不卡电影| 欧美多人爱爱视频网站| 三级黄色片网站| 自拍一区在线观看| 91丨porny丨户外露出| 午夜精品久久久久久久男人的天堂| 久久成年人网站| 国产一二三区在线观看| 久久丁香综合五月国产三级网站| 在线看日韩av| 天堂av在线网站| 福利在线午夜| 青娱乐精品视频在线| 中文字幕日韩欧美| 色婷婷综合网站| 蜜桃av在线| 久久色成人在线| 91pron在线| 久久久久99精品成人片试看| 清纯唯美激情亚洲| 日韩美女精品在线| 91在线视频成人| 香蕉视频一区二区| 国产一区二区亚洲| 欧美日韩国产在线播放网站| 激情五月五月婷婷| 成人毛片在线免费观看| 国产精品v欧美精品v日本精品动漫| 日韩欧美国产综合在线一区二区三区| 嫩草影院中文字幕| 性插视频在线观看| 青青青爽久久午夜综合久久午夜| 欧美亚洲另类制服自拍| 91精品国自产在线| 久久久精品一区二区毛片免费看| 中文字幕一区二区不卡| 成人国产一区二区| 一二三区免费视频| 一区二区三区午夜视频| 日韩精品中午字幕| 麻豆传媒在线看| 亚洲妇女成熟| 欧美性猛交xxxx久久久| 亚洲精品一区二区三区蜜桃久| 国产精品久久婷婷| 在线看片一区| 一区二区三区国产在线观看| 亚洲a v网站| re久久精品视频| 欧美成人猛片aaaaaaa| 精品免费国产一区二区| 四虎永久免费地址| 成人看片网页| 亚洲激情自拍视频| 欧美 日韩 国产精品| 国产在线观看高清视频| 福利一区二区在线观看| 国产精品视频一区二区三区四 | 亚洲一区中文字幕永久在线| 麻豆国产精品官网| 91精品国产九九九久久久亚洲| 天堂av免费在线| 无码少妇一区二区三区| 欧美日韩成人激情| 精产国品一区二区三区| 国产精品欧美大片| 欧美一区二区精品久久911| caopor在线视频| 色999韩欧美国产综合俺来也| 福利二区91精品bt7086| 菠萝蜜视频在线观看入口| 久久香蕉av| 国产精品久久久久久久久晋中| 国产资源第一页| 无遮挡动作视频在线观看免费入口| www.欧美.com| 亚洲精品一区二区毛豆| 欧洲性视频在线播放| 色狠狠av一区二区三区| 欧美黄色免费网址| 日韩精品99| 色噜噜狠狠成人网p站| 深夜黄色小视频| 国精产品一区一区三区四川| 日韩一区二区在线免费观看| 九九九九九九九九| 成人看片黄a免费看视频| 欧美精品高清视频| 黄色手机在线视频| 国产精品流白浆在线观看| 最近日韩中文字幕中文| 人妻aⅴ无码一区二区三区| 亚洲电影男人天堂| 亚洲精品中文字幕av| 四虎影院中文字幕| 亚洲综合五月| 国产精品成人播放| 中文字幕永久在线视频| 另类的小说在线视频另类成人小视频在线| 成人性色av| 污污视频在线免费看| 国产精品毛片久久久久久| 亚洲激情一区二区三区| 九九色在线视频| 欧美高清视频在线高清观看mv色露露十八| 国产亚洲无码精品| 亚洲国产免费| 国产成人精品一区| 中文字字幕在线中文乱码| 99久久精品免费看| 日本不卡久久| 99se视频在线观看| 亚洲欧美乱综合| 浴室偷拍美女洗澡456在线| 日韩美女在线看免费观看| 亚洲精品国偷自产在线99热| 亚洲精品国产熟女久久久| 亚洲大胆在线| 国产福利久久精品| 日本不卡影院| 日韩欧美电影一二三| 少妇人妻丰满做爰xxx| 极品中文字幕一区| 97se国产在线视频| 91亚洲天堂| 福利一区视频在线观看| 在线中文字日产幕| 亚洲欧美日本伦理| 7777精品视频| 日韩大片b站免费观看直播| 午夜精品在线看| 邪恶网站在线观看| 日韩中文欧美| 97免费中文视频在线观看| 亚洲a视频在线| 国产亚洲1区2区3区| 亚洲一区高清| 四虎视频在线精品免费网址| 久久久91精品国产一区不卡| 国产一级中文字幕| 人禽交欧美网站| 亚洲精品一区二区三区樱花| 欧美a一级片| 久久五月情影视| 国内精品福利视频| 久久99精品久久久久久| av不卡在线免费观看| 午夜影院在线播放| 亚洲欧美综合区自拍另类| 青青草在线观看视频| 久久综合图片| 成人黄色片视频网站| free性m.freesex欧美| 在线播放一区二区三区| 九九精品视频免费| 成人深夜视频在线观看| 精品一区二区成人免费视频| 久久久久久爱| 日韩专区在线播放| 成人毛片18女人毛片| 久久久精品免费网站| 国产精品成人久久电影| 只有精品亚洲| 亚洲视频网站在线观看| 亚洲中文一区二区三区| 亚洲在线观看免费视频| 天堂网在线免费观看| 欧美91精品| 亚洲r级在线观看| av播放在线| 日韩欧美一级在线播放| 九九热在线免费观看| 国产精品伦一区| 亚洲欧美综合视频| 日本亚洲三级在线| 青草网在线观看| 欧美限制电影| 国产精品扒开腿做| 午夜激情在线| 欧美一区二区女人| 亚洲国产精品无码久久久| 自拍偷拍亚洲激情| 国产精品一级黄片| 亚洲在线电影| 精品一区二区三区国产| 99在线视频影院| 国产丝袜一区二区三区| 中文字幕+乱码+中文| 亚洲电影中文字幕在线观看| www.555国产精品免费| 亚洲一级高清| 亚洲在线色站| 国产探花一区| 好吊妞www.84com只有这里才有精品 | 久久精品免费在线观看| 亚洲精品激情视频| 国内久久精品视频| 在线观看免费黄色片| 色天下一区二区三区| 97se在线视频| 亚洲精品aa| 国产精品一区二区电影| 免费黄网站在线| 日韩精品一区二区三区中文不卡| 中文字幕 国产精品| 国产免费久久精品| 亚洲午夜精品一区| 日本系列欧美系列| 国产性xxxx18免费观看视频| 精品成人影院| 噜噜噜噜噜久久久久久91| 成人自拍av| 2019中文字幕在线观看| 国产美女福利在线观看| 日韩精品视频免费专区在线播放| 国产午夜麻豆影院在线观看| 午夜久久福利影院| 国产精品第9页| 国产欧美一区二区在线| 一级性生活大片| 激情偷乱视频一区二区三区| 日本在线观看免费视频| 日韩成人免费电影| 一区二区三区免费播放| 日韩不卡一二三区| 亚洲黄色av网址| 免费欧美在线视频| 久草视频这里只有精品| 欧美日韩1080p| 日韩欧美视频第二区| 国产亚洲观看| 91免费看片在线| 欧美黄色一级| 99精品国产一区二区| 综合久久成人| 国产精品一区二区三区久久| 韩国成人在线| 国内精品久久久久久影视8| 国产黄色片在线播放| 亚洲天堂免费视频| 91麻豆成人精品国产| 亚洲成人手机在线| 日韩精品久久久久久久| 午夜精品福利一区二区蜜股av| 欧美三日本三级少妇99| 日本乱人伦aⅴ精品| 中文字幕永久在线观看| 日韩欧美区一区二| 色视频在线观看福利| 国产一区二区三区丝袜| 毛片在线不卡| 久久免费少妇高潮久久精品99| 欧美gv在线| 国产精品精品一区二区三区午夜版 | wwwxxxx在线观看| 国产成人午夜片在线观看高清观看| 国模杨依粉嫩蝴蝶150p| 日韩av不卡一区二区| 午夜啪啪小视频| 成人午夜视频福利| 日韩一区二区a片免费观看| 国产精品护士白丝一区av| 青娱乐国产盛宴| 色国产精品一区在线观看| 91高潮大合集爽到抽搐| 亚洲国产精久久久久久| 国产三级小视频| 欧美丰满少妇xxxbbb| 成人爽a毛片一区二区| 亚洲欧洲日产国码av系列天堂| 老司机99精品99| 91黄色8090| 91精品网站在线观看| 精品午夜一区二区三区| 91欧美国产| 综合视频在线观看| 99精品久久| 欧美日韩二三区| 精品999日本| 国产免费又粗又猛又爽| 国产91在线|亚洲| 97在线观看免费视频| 亚洲精品日产精品乱码不卡| 伦av综合一区| 欧美一级高清片在线观看| 九色国产在线观看| 欧美黄色免费网站| 欧美一区=区三区| 欧美另类高清视频在线| 国产一区二区三区网| 日本精品久久久久久久久久| 日韩视频在线一区二区三区| 午夜免费福利视频在线观看| 紧缚捆绑精品一区二区| 变态另类丨国产精品| 一区二区三区.www| 一道本无吗一区| 国产小视频国产精品| 精品丝袜在线| 国产无套精品一区二区| 亚洲免费观看高清完整版在线观| 国产女教师bbwbbwbbw| 久久狠狠亚洲综合| 久久午夜福利电影| 欧美网站在线观看| 手机在线观看毛片| 亚洲图中文字幕| 麻豆mv在线看| 国产精品美女黄网| 国产一区二区三区不卡视频网站| 男人的天堂avav| 久久国产精品72免费观看| 免费黄色片网站| 91成人国产精品| 国产理论视频在线观看| 在线亚洲国产精品网| 国模视频一区| 日本一区二区三不卡| 美女网站久久| 91精品999| 国产精品欧美极品| 在线免费av片| 视频一区视频二区国产精品 | 欧美成人高清在线| 国产精品视频网| 婷婷久久一区| 自拍日韩亚洲一区在线| 日韩精品国产精品| 日韩精品无码一区二区三区久久久| 狠狠做深爱婷婷久久综合一区 | 2022国产精品视频| 五月婷婷中文字幕| 亚洲一级黄色av| 青青草国产一区二区三区| 一区二区三区不卡在线| 国内一区二区在线| 九九热这里有精品视频| 精品久久一区二区| 日本不卡网站| 日韩精品久久久| 激情亚洲综合在线| 久久r这里只有精品| 337p日本欧洲亚洲大胆精品| 丝袜老师在线| 亚洲成人午夜在线| 国内精品视频666| 国产网站在线看| 亚洲精品一区二区网址| 国产69精品久久久久9999人| 国产伦精品一区二区三区四区视频 | 裸体女人亚洲精品一区| 中文字幕日韩在线| 日本韩国欧美在线观看| 国产农村妇女毛片精品久久麻豆| 97在线视频人妻无码| 欧美激情视频在线观看| 亚洲成av在线| 佐佐木明希av| 99久久久国产精品| 中文字幕无码乱码人妻日韩精品| 麻豆成人在线看| 免费一区二区| 日本a在线免费观看| 久久久久久一二三区| 国产精品视频久久久久久| 97碰在线观看| 亚洲国产精品久久久天堂| 天天爱天天操天天干| 亚洲乱码国产乱码精品精的特点| 少妇高潮一区二区三区69| 国产精品日韩久久久久| 欧美精品自拍| 成人午夜剧场视频网站| 日韩一级视频免费观看在线| 波多野结衣亚洲| 麻豆av一区二区三区| 精品一区二区三区在线观看 | 最新国产露脸在线观看| 蜜桃免费一区二区三区| 国产精一区二区三区|