成人怡红院-成人怡红院视频在线观看-成人影视大全-成人影院203nnxyz-美女毛片在线看-美女免费黄

站長資訊網(wǎng)
最全最豐富的資訊網(wǎng)站

深入了解Vue中的雙端diff 算法

diff 算法是渲染器中最復雜的部分,本篇文章帶大家了解一下Vue中的雙端diff 算法,希望對大家有所幫助!

深入了解Vue中的雙端diff 算法

Vue 和 React 都是基于 vdom 的前端框架,組件渲染會返回 vdom,渲染器再把 vdom 通過增刪改的 api 同步到 dom。(學習視頻分享:vuejs視頻教程)

當再次渲染時,會產(chǎn)生新的 vdom,渲染器會對比兩棵 vdom 樹,對有差異的部分通過增刪改的 api 更新到 dom。

這里對比兩棵 vdom 樹,找到有差異的部分的算法,就叫做 diff 算法。

diff 算法是渲染器中最復雜的部分,也是面試的熱點問題。今天我們就通過 Vue 的 diff 算法來探究下 diff 算法吧。

diff 算法

我們知道,兩棵樹做 diff,復雜度是 O(n^3) 的,因為每個節(jié)點都要去和另一棵樹的全部節(jié)點對比一次,這就是 n 了,如果找到有變化的節(jié)點,執(zhí)行插入、刪除、修改也是 n 的復雜度。所有的節(jié)點都是這樣,再乘以 n,所以是 O(n * n * n) 的復雜度。

深入了解Vue中的雙端diff 算法

這樣的復雜度對于前端框架來說是不可接受的,這意味著 1000 個節(jié)點,渲染一次就要處理 1000 * 1000 * 1000,一共 10 億次。

所以前端框架的 diff 約定了兩種處理原則:只做同層的對比,type 變了就不再對比子節(jié)點。

因為 dom 節(jié)點做跨層級移動的情況還是比較少的,一般情況下都是同一層級的 dom 的增刪改。

這樣只要遍歷一遍,對比一下 type 就行了,是 O(n) 的復雜度,而且 type 變了就不再對比子節(jié)點,能省下一大片節(jié)點的遍歷。另外,因為 vdom 中記錄了關聯(lián)的 dom 節(jié)點,執(zhí)行 dom 的增刪改也不需要遍歷,是 O(1)的,整體的 diff 算法復雜度就是 O(n) 的復雜度。

深入了解Vue中的雙端diff 算法

1000 個節(jié)點渲染一次最多對比 1000 次,這樣的復雜度就是可接受的范圍了。

但是這樣的算法雖然復雜度低了,卻還是存在問題的。

比如一組節(jié)點,假設有 5 個,類型是 ABCDE,下次渲染出來的是 EABCD,這時候逐一對比,發(fā)現(xiàn) type 不一樣,就會重新渲染這 5 個節(jié)點。

而且根據(jù) type 不同就不再對比子節(jié)點的原則,如果這些節(jié)點有子節(jié)點,也會重新渲染。

dom 操作是比較慢的,這樣雖然 diff 的算法復雜度是低了,重新渲染的性能也不高。

所以,diff 算法除了考慮本身的時間復雜度之外,還要考慮一個因素:dom 操作的次數(shù)。

上面那個例子的 ABCDE 變?yōu)?EABCD,很明顯只需要移動一下 E 就行了,根本不用創(chuàng)建新元素。

但是怎么對比出是同個節(jié)點發(fā)生了移動呢?

判斷 type 么? 那不行,同 type 的節(jié)點可能很多,區(qū)分不出來的。

最好每個節(jié)點都是有唯一的標識。

所以當渲染一組節(jié)點的時候,前端框架會讓開發(fā)者指定 key,通過 key 來判斷是不是有點節(jié)點只是發(fā)生了移動,從而直接復用。

這樣,diff 算法處理一組節(jié)點的對比的時候,就要根據(jù) key 來再做一次算法的優(yōu)化。

我們會把基于 key 的兩組節(jié)點的 diff 算法叫做多節(jié)點 diff 算法,它是整個 vdom 的 diff 算法的一部分。

接下來我們來學習一下多節(jié)點 diff 算法:

簡單 diff

假設渲染 ABCD 一組節(jié)點,再次渲染是 DCAB,這時候怎么處理呢?

多節(jié)點 diff 算法的目的是為了盡量復用節(jié)點,通過移動節(jié)點代替創(chuàng)建。

所以新 vnode 數(shù)組的每個節(jié)點我們都要找下在舊 vnode 數(shù)組中有沒有對應 key 的,有的話就移動到新的位置,沒有的話再創(chuàng)建新的。

也就是這樣的:

const oldChildren = n1.children const newChildren = n2.children  let lastIndex = 0 // 遍歷新的 children for (let i = 0; i < newChildren.length; i++) {     const newVNode = newChildren[i]     let j = 0     let find = false     // 遍歷舊的 children     for (j; j < oldChildren.length; j++) {       const oldVNode = oldChildren[j]       // 如果找到了具有相同 key 值的兩個節(jié)點,則調(diào)用 patch 函數(shù)更新       if (newVNode.key === oldVNode.key) {         find = true         patch(oldVNode, newVNode, container)                  處理移動...                  break //跳出循環(huán),處理下一個節(jié)點       }    }    // 沒有找到就是新增了    if (!find) {       const prevVNode = newChildren[i - 1]       let anchor = null       if (prevVNode) {         anchor = prevVNode.el.nextSibling       } else {         anchor = container.firstChild       }       patch(null, newVNode, container, anchor)    } }

這里的 patch 函數(shù)的作用是更新節(jié)點的屬性,重新設置事件監(jiān)聽器。如果沒有對應的舊節(jié)點的話,就是插入節(jié)點,需要傳入一個它之后的節(jié)點作為錨點 anchor。

我們遍歷處理新的 vnode:

先從舊的 vnode 數(shù)組中查找對應的節(jié)點,如果找到了就代表可以復用,接下來只要移動就好了。

如果沒找到,那就執(zhí)行插入,錨點是上一個節(jié)點的 nextSibling。

深入了解Vue中的雙端diff 算法

那如果找到了可復用的節(jié)點之后,那移動到哪里呢?

其實新的 vnode 數(shù)組中記錄的順序就是目標的順序。所以把對應的節(jié)點按照新 vnode 數(shù)組的順序來移動就好了。

const prevVNode = newChildren[i - 1] if (prevVNode) {     const anchor = prevVNode.el.nextSibling     insert(newVNode.el, container, anchor) }

要插入到 i 的位置,那就要取 i-1 位置的節(jié)點的 nextSibling 做為錨點來插入當前節(jié)點。

深入了解Vue中的雙端diff 算法

但是并不是所有的節(jié)點都需要移動,比如處理到第二個新的 vnode,發(fā)現(xiàn)它在舊的 vnode 數(shù)組中的下標為 4,說明本來就是在后面了,那就不需要移動了。反之,如果是 vnode 查找到的對應的舊的 vnode 在當前 index 之前才需要移動。

也就是這樣:

let j = 0 let find = false // 遍歷舊的 children for (j; j < oldChildren.length; j++) {     const oldVNode = oldChildren[j]     // 如果找到了具有相同 key 值的兩個節(jié)點,則調(diào)用 patch 函數(shù)更新之     if (newVNode.key === oldVNode.key) {         find = true         patch(oldVNode, newVNode, container)          if (j < lastIndex) { // 舊的 vnode 數(shù)組的下標在上一個 index 之前,需要移動           const prevVNode = newChildren[i - 1]           if (prevVNode) {             const anchor = prevVNode.el.nextSibling             insert(newVNode.el, container, anchor)           }         } else {// 不需要移動           // 更新 lastIndex           lastIndex = j         }         break     } }

查找新的 vnode 在舊的 vnode 數(shù)組中的下標,如果找到了的話,說明對應的 dom 就是可以復用的,先 patch 一下,然后移動。

移動的話判斷下下標是否在 lastIndex 之后,如果本來就在后面,那就不用移動,更新下 lastIndex 就行。

如果下標在 lastIndex 之前,說明需要移動,移動到的位置前面分析過了,就是就是新 vnode 數(shù)組 i-1 的后面。

這樣,我們就完成了 dom 節(jié)點的復用和移動。

新的 vnode 數(shù)組全部處理完后,舊的 vnode 數(shù)組可能還剩下一些不再需要的,那就刪除它們:

// 遍歷舊的節(jié)點 for (let i = 0; i < oldChildren.length; i++) {     const oldVNode = oldChildren[i]     // 拿著舊 VNode 去新 children 中尋找相同的節(jié)點     const has = newChildren.find(       vnode => vnode.key === oldVNode.key     )     if (!has) {       // 如果沒有找到相同的節(jié)點,則移除       unmount(oldVNode)     } }

這樣,我們就完成了兩組 vnode 的 diff 和對應 dom 的增刪改。

小結(jié)一下:

diff 算法的目的是根據(jù) key 復用 dom 節(jié)點,通過移動節(jié)點而不是創(chuàng)建新節(jié)點來減少 dom 操作。

對于每個新的 vnode,在舊的 vnode 中根據(jù) key 查找一下,如果沒查找到,那就新增 dom 節(jié)點,如果查找到了,那就可以復用。

復用的話要不要移動要判斷下下標,如果下標在 lastIndex 之后,就不需要移動,因為本來就在后面,反之就需要移動。

最后,把舊的 vnode 中在新 vnode 中沒有的節(jié)點從 dom 樹中刪除。

這就是一個完整的 diff 算法的實現(xiàn)。

深入了解Vue中的雙端diff 算法

這個 diff 算法我們是從一端逐個處理的,叫做簡單 diff 算法。

簡單 diff 算法其實性能不是最好的,比如舊的 vnode 數(shù)組是 ABCD,新的 vnode 數(shù)組是 DABC,按照簡單 diff 算法,A、B、C 都需要移動。

那怎么優(yōu)化這個算法呢?

從一個方向順序處理會有這個問題,那從兩個方向同時對比呢?

這就是雙端 diff 算法:

雙端 diff

簡單 diff 算法能夠?qū)崿F(xiàn) dom 節(jié)點的復用,但有的時候會做一些沒必要的移動。雙端 diff 算法解決了這個問題,它是從兩端進行對比。

我們需要 4 個指針,分別指向新舊兩個 vnode 數(shù)組的頭尾:

深入了解Vue中的雙端diff 算法

頭和尾的指針向中間移動,直到 oldStartIdx <= oldEndIdx 并且 newStartIdx <= newEndIdx,說明就處理完了全部的節(jié)點。

每次對比下兩個頭指針指向的節(jié)點、兩個尾指針指向的節(jié)點,頭和尾指向的節(jié)點,是不是 key是一樣的,也就是可復用的。

如果是可復用的話就直接用,調(diào)用 patch 更新一下,如果是頭尾這種,還要移動下位置。

也就是這樣的:

while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {   if (oldStartVNode.key === newStartVNode.key) { // 頭頭     patch(oldStartVNode, newStartVNode, container)     oldStartVNode = oldChildren[++oldStartIdx]     newStartVNode = newChildren[++newStartIdx]   } else if (oldEndVNode.key === newEndVNode.key) {//尾尾     patch(oldEndVNode, newEndVNode, container)     oldEndVNode = oldChildren[--oldEndIdx]     newEndVNode = newChildren[--newEndIdx]   } else if (oldStartVNode.key === newEndVNode.key) {//頭尾,需要移動     patch(oldStartVNode, newEndVNode, container)     insert(oldStartVNode.el, container, oldEndVNode.el.nextSibling)      oldStartVNode = oldChildren[++oldStartIdx]     newEndVNode = newChildren[--newEndIdx]   } else if (oldEndVNode.key === newStartVNode.key) {//尾頭,需要移動     patch(oldEndVNode, newStartVNode, container)     insert(oldEndVNode.el, container, oldStartVNode.el)      oldEndVNode = oldChildren[--oldEndIdx]     newStartVNode = newChildren[++newStartIdx]   } else {          // 頭尾沒有找到可復用的節(jié)點   } }

頭頭和尾尾的對比比較簡單,頭尾和尾頭的對比還要移動下節(jié)點。

比如舊 vnode 的頭節(jié)點是新的 vnode 的尾節(jié)點,那就要把它移動到舊的 vnode 的尾節(jié)點的位置。

也就是:

insert(oldStartVNode.el, container, oldEndVNode.el.nextSibling)

插入節(jié)點的錨點節(jié)點是 oldEndVNode 對應的 dom 節(jié)點的 nextSibling。

如果舊 vnode 的尾節(jié)點是新 vnode 的頭結(jié)點,那就要把它移動到舊 vnode 的頭結(jié)點的位置。

也就是:

insert(oldEndVNode.el, container, oldStartVNode.el)

插入節(jié)點的錨點節(jié)點是 oldStartVNode 對應的 dom 節(jié)點(因為要插在它之前)。

從雙端進行對比,能盡可能的減少節(jié)點移動的次數(shù)。

當然,還要處理下如果雙端都沒有可復用節(jié)點的情況:

如果雙端都沒有可復用節(jié)點,那就在舊節(jié)點數(shù)組中找,找到了就把它移動過來,并且原位置置為 undefined。沒找到的話就插入一個新的節(jié)點。

也就是這樣:

const idxInOld = oldChildren.findIndex(   node => node.key === newStartVNode.key ) if (idxInOld > 0) {   const vnodeToMove = oldChildren[idxInOld]   patch(vnodeToMove, newStartVNode, container)   insert(vnodeToMove.el, container, oldStartVNode.el)   oldChildren[idxInOld] = undefined } else {   patch(null, newStartVNode, container, oldStartVNode.el) }

因為有了一些 undefined 的節(jié)點,所以要加上空節(jié)點的處理邏輯:

if (!oldStartVNode) {     oldStartVNode = oldChildren[++oldStartIdx] } else if (!oldEndVNode) {     oldEndVNode = newChildren[--oldEndIdx] }

這樣就完成了節(jié)點的復用和移動的邏輯。

那確實沒有可復用的節(jié)點的那些節(jié)點呢?

經(jīng)過前面的移動之后,剩下的節(jié)點都被移動到了中間,如果新 vnode 有剩余,那就批量的新增,如果舊 vnode 有剩余那就批量的刪除。

因為前面一個循環(huán)的判斷條件是 oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx,這樣如果 old vnode 多了,最后 newStartIdx 會小于 newEndIdx。如果 new vnode 多了,最后 oldStartIdx 會小于 oldEndIdx。

所以判斷條件是這樣的:

if (oldEndIdx < oldStartIdx && newStartIdx <= newEndIdx) {   // 添加新節(jié)點   for (let i = newStartIdx; i <= newEndIdx; i++) {     patch(null, newChildren[i], container, oldStartVNode.el)   } } else if (newEndIdx < newStartIdx && oldStartIdx <= oldEndIdx) {   // 移除操作   for (let i = oldStartIdx; i <= oldEndIdx; i++) {     unmount(oldChildren[i])   } }

這樣就是一個完整的 diff 算法了,包括查找可復用節(jié)點和移動節(jié)點、新增和刪除節(jié)點。

而且因為從兩側(cè)查找節(jié)點,會比簡單 diff 算法性能更好一些。

比如 ABCD 到 DABC,簡單 diff 算法需要移動 ABC 三個節(jié)點,而雙端 diff 算法只需要移動 D 一個節(jié)點。

小結(jié)一下:

雙端 diff 是頭尾指針向中間移動的同時,對比頭頭、尾尾、頭尾、尾頭是否可以復用,如果可以的話就移動對應的 dom 節(jié)點。

如果頭尾沒找到可復用節(jié)點就遍歷 vnode 數(shù)組來查找,然后移動對應下標的節(jié)點到頭部。

最后還剩下舊的 vnode 就批量刪除,剩下新的 vnode 就批量新增。

深入了解Vue中的雙端diff 算法

雙端 diff 算法是 Vue2 采用的 diff 算法,性能還不錯。

后來,Vue3 又對 diff 算法進行了一次升級,叫做快速 diff 算法。這個后面再講。

總結(jié)

React 和 Vue 都是基于 vdom 的前端框架,組件產(chǎn)生 vdom,渲染器再把 vdom 通過增刪改的 dom api 更新到 dom。

當再次渲染出 vdom 時,就要新舊兩棵 vdom 樹做 diff,只更新變化的 dom 節(jié)點。

兩棵樹的 diff 是 O(n^3) 的,時間復雜度太高,因此前端框架規(guī)定了只做同層 diff,還有 type 不一樣就認為節(jié)點不一樣,不再對比子節(jié)點。這樣時間復雜度一下子就降到了 O(n)。

但是對于多個子字節(jié)點的 diff 不能粗暴的刪除和新增,要盡量復用已有的節(jié)點,也就是通過移動代替新增。

所以多節(jié)點的時候,要指定 key,然后 diff 算法根據(jù) key 來查找和復用節(jié)點。

簡單 diff 算法是依次根據(jù) key 查找舊節(jié)點的,移動的話通過 lastIndex 判斷,大于它就不用動,小于它才需要移動。剩下的節(jié)點再批量刪除和新增。

但是簡單 diff 算法局限性還是比較大的,有些情況下性能并不好,所以 vue2 用的是雙端 diff 算法。

雙端 diff 算法是頭尾指針向中間移動,分別判斷頭尾節(jié)點是否可以復用,如果沒有找到可復用的節(jié)點再去遍歷查找對應節(jié)點的下標,然后移動。全部處理完之后也要對剩下的節(jié)點進行批量的新增和刪除。

其實 diff 算法最重要的就是找到可復用的節(jié)點,然后移動到正確的位置。只不過不同的算法查找順序不一樣。

vue2 是用的雙端 diff 的算法,而 vue3 則通過最長遞增子序列的算法做了進一步的優(yōu)化,關于優(yōu)化后的 diff 算法,我們之后再聊。

【相關視頻教程推薦:web前端】

贊(0)
分享到: 更多 (0)
?
網(wǎng)站地圖   滬ICP備18035694號-2    滬公網(wǎng)安備31011702889846號
YY8098影视理论无码专区| 吃奶呻吟打开双腿做受是免费视频| 777国产偷窥盗摄精品品在线| 最新亚洲春色AV无码专区| 综合精品欧美日韩国产在线 | 久久人人做人人妻人人玩精品VA| 麻豆国产蜜桃臀视频在线观看| 男男黄GAY片免费网站WWW| 去部队探亲晚上叫太大声| 色婷婷综合久久久久中文一区二区| 无码成人黄动漫在线观看| 亚洲国产A∨无码中文777| 泳池里强摁做开腿呻吟| VPSWINDOWS另类精品| 国产AⅤ无码专区亚洲AV琪琪| 国产免费AV片在线播放| 久久大蕉香蕉免费| 年轻 娇小 亚洲人 日本语 夹| 日本熟妇人妻ⅩXXXX| 无码一区二区三区亚洲人妻| 亚洲乱码AV中文一区二区| 坐着轮流提双腿能起到什么效果 | 曰本伦理漂亮妈妈| 波多野结衣AV无码| 国产乱子伦一区二区三区=| 久本草在线中文字幕| 欧美顶级METART裸体全部自| 少妇乱人伦无码视频| 亚洲国产AV无码精品| 18禁美女黄网站色大片免费看| 插花弄玉曲径通幽| 国产午夜福利亚洲第一| 老熟妇高潮一区二区三区网| 日本乱偷人妻中文字幕在线| 性色AV.网站免费| 中文在线中文资源| 公翁的粗大放进我的秘密小说 | 国产98色在线 | 国| 精品无码一区二区三区亚洲桃色| 欧美美女多人群交视频| 无遮挡边摸边吃奶边做视频免费| 一本大道大臿蕉无码视频| 白丝?扒腿自慰爽出白浆| 国产区图片区小说区亚洲区| 秘密列车在线全集免费观看| 少妇高潮XXXⅩ白浆699| 亚洲精品又大又粗| 白丝JK高潮喷水在线观看| 韩漫网站在线看免费无删减漫画 | 久久99精品久久久久久HB| 人妻丰满AV无码中文字幕| 亚洲AV无码国产精品麻豆天美| 97久久国产亚洲精品超碰热| 国产伦精品一区二区三区免.费 | AV无码中文字幕不卡一区二区三| 国产清纯白嫩大学生正在播放 | 久久精品国产亚洲AV成人| 日韩成人无码AV| 亚洲一区二区三区无码国产| 大炕上的肉体交换农村乱睡| 久久久久久久精品无码AV少妇| 色综合伊人色综合网站| 野花影视免费观看高清| 国产粗话肉麻对白在线播放| 男吃奶玩乳尖高潮视频午夜| 亚洲 欧洲 小说 自拍| AV无码中文字幕不卡一区二区三| 好大好湿好硬顶到了好爽视频| 全免费A级毛片免费看| 亚洲人成网站色7799| 国产GAYSEXCHINA男外| 免费无码又爽又刺激动态图| 亚洲AⅤ精品无码一区二区PRO| WRITEAS前后双插头| 精品无人乱码一区二区三区| 天天拍夜夜添久久精品| 99国精产品灬源码1688| 精品国模一区二区三区| 少妇人妻无码专区视频| 7777色情ⅩXXX欧美色妇| 精产国品一二三产品区别在| 少妇激情一区二区三区视频| 99久久亚洲综合精品成人| 教室抽插调教老师小说| 熟妇的滚烫的肉唇翻进翻出| 80S国产成年女人毛片| 姬小满无限奖励别人的英雄| 四季亚洲精品成人AV无码网站| 99久久精品国产第一页| 久久久WWW成人免费精品| 性色A码一区二区三区天美传媒| 被多人玩弄的烂货苏妖精| 蜜芽亚洲日韩欧美国产高清ΑV| 亚洲高清专区日韩精品| 国产精品VIDEOSSEX国产| 强奷漂亮少妇高潮麻豆| 中国内地毛片免费高清| 极品人妻系列人妻30P| 无码国产精品一区二区免费式直播 | 中文字幕日本六区小电影| 精品少妇爆乳无码AⅤ区| 五十路熟妇高熟无码视频| 大爷你的太大了我| 强CAO出水嗯啊高潮了H漫画| 中文字幕AV一区中文字幕天堂 | 欧美一性一交一免费看| 在线天堂中文最新版| 久久99国产精品久久99果冻传| 性饥渴少妇做私密SPA| 国产白嫩护士被弄高潮| 日韩欧美国产精品亚洲二区| AV一本大道香蕉大在线| 免费高清中文字幕MV| 亚洲综合色AAA成人无码| 精JAVAPARSER乱偷| 亚洲成AV人片无码BT种子下载| 国产成人无码久久久精品一| 色777狠狠狠综合| 暴躁老姐的CSGO心得分享| 欧美极品在线观看| 18禁真人床震无遮挡免费| 美女图片禁欲系高级感| 怡红院A∨人人爰人人爽| 久久精品无码一区二区无码 | SUNTEK中老年人女妈妈秋装| 欧美成人精品视频在线观看| 2023国精产品一二三四区| 免费能直接看黄的视频| 稚嫩的花苞被老师开了| 美女裸体跪姿扒开屁股无内裤| 野花高清在线电影观看免费视频 | 亚洲欧洲专线一区| 精品人妻一区二区三区视频| 亚洲国产一区二区三区亚瑟| 精品久久久久久无码免费| 亚洲欧美成人在线| 久久久久久国产精品免费无码| 亚洲男人成人性天堂网站| 久久精品国产亚洲AV麻豆AⅤ| 亚洲中文字幕成人无码| 久久婷婷国产综合精品| 伊人久久大香线蕉午夜AV| 蜜桃国产精品乱码一区二区三区| 做I爱直播APP| 欧美制服丝袜人妻另类| 波多野结衣的影片| 少妇又紧又深又湿又爽视频| 国产精品对白刺激久久久| 性妇WBBBB搡BBBB嗓小说| 黑人强伦姧人妻完整版| 亚洲日韩∨A无码中文字幕| 老师掀起裙子让我挺进 | 亚洲旡码A∨一区二区三区| 久久精品国产亚洲AV麻豆甜| 在线观看国产精选免费| 欧美猛片BBBBBⅩXXXX| 超高清欧美VIDEOSSEXO| 特殊重囗味SM在线观看无码| 国产无遮挡18禁网站免费| 亚洲国产婷婷六月丁香| 久久无码国产专区精品| AV天堂亚洲国产AV| 色婷婷AV一区二区三区4k岛国| 国产免费无遮挡吸奶头视频| 亚洲精品无码专区在线| 麻豆国产成人AV| 办公室撕开奶罩揉吮奶头在线观看| 少妇饥渴偷公乱第一章全文| 国内精品久久久久久中文字幕 | 久久久99精品成人片中文字幕| 77777亚洲午夜久久多人| 日日摸夜夜添狠狠添欧美| 国产网红在线_电影频道| 亚洲综合蜜臀AV| 欧美亚洲国产片在线播放 | 中文字幕欧美人妻精品一区| 人妻丰满熟AV无码区HD| 国产精品视频一区二区三区无码 | 婷婷成人五月综合激情| 精品国精品国产自在久国产应用男 | YSL千人千色T9T9T9T| 我和几个亲戚都做了爱| 精品推荐国产AV剧情| AⅤ一区二区三区无卡无码| 睡美人免费观看完整版西瓜| 精品亚洲国产成人| 啊灬啊灬啊灬快灬高潮少妇软件 | 幻女FREE性俄罗斯毛片| 2021韩剧在线观看韩剧网| 熟妇阿 HD中文电影| 久久AV无码ΑV高潮ΑV喷吹| VODAFONEWIFI暴力| 亚洲 中文字幕在线播| 美国少归BVBV| 国产V综合V亚洲欧| 亚洲制服丝袜无码AV在线| 日本乱偷互换人妻中文字幕| 极品性荡少妇一区二区| 宝贝感受到它在爱你吗病娇小说| 亚洲AV无码不卡|