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

淺析 Preact Signals 及實現原理

開發 前端
Preact Signals 本身在狀態管理上區別于 React Hooks 上的一個點在于: Signals 本身是基于應用的狀態圖去做數據更新,而 Hooks 本身則是依附于 React 的組件樹去進行更新。

介紹

Preact Signals 是 Preact 團隊在22年9月引入的一個特性。我們可以將它理解為一種細粒度響應式數據管理的方式,這個在很多前端框架中都會有類似的概念,例如 SolidJS、Vue3 的 Reactivity、Svelte 等等。

Preact Signals 在命名上參考了 SolidJS 的 Signals 的概念,不過兩個框架的實現方式和行為都有一些區別。在 Preact Signals 中,一個 signal 本質上是個擁有 .value 屬性的對象,你可以在一個 React 組件中按照如下方式使用:

import { signal } from '@preact/signals';

const count = signal(0);

function Counter() {
  const value = count.value;
  
  return (
    <div>
      <p>Count: {value}</p>
      <button onClick={() => count.value ++}>Click</button>
    </div>
  )
}

通過這個例子,我們可以看到 Signal 不同于 React Hooks 的地方: 它是可以直接在組件外部調用的。

同時這里我們也可以看到,在組件中聲明了一個叫 count 的 signal 對象,但組件在消費對應的 signal 值的時候,只用訪問對應 signal 對象的 .value 值即可。

在開始具體的介紹之前,筆者先從 Preact 官方文檔中貼幾個關于 Signal API 的介紹,讓讀者對 Preact Signals 這套數據管理方式有個基本的了解。

API

以下為 Preact Signals 提供的一些 Common API:

signal(initialValue)

這個 API 表示的就是個最普通的 Signals 對象,它算是 Preact Signals 整個響應式系統最基礎的地方。

當然,在不同的響應式庫中,這個最基礎的原語對象也會有不同的名稱,例如 Mobx、RxJS 的 Observers,Vue 的 Refs。而 Preact 這里參考了和 SolidJS 一樣的術語 signal。

Signal 可以表示包裝在響應式里層的任意 JS 值類型,你可以創建一個帶有初始值的 signal,然后可以隨意讀和更新它:

import { signal } from '@preact/signals-core';

const s = signal(0);
console.log(s.value); // Console: 0

s.value = 1;
console.log(s.value); // Console: 1

computed(fn)

Computed Signals 通過 computed(fn) 函數從其它 signals 中派生出新的 signals 對象:

import { signal, computed } from '@preact/signals-core';

const s1 = signal('hello');
const s2 = signal('world');

const c = computed(() => {
  return s1.value + " " + s2.value
})

不過需要注意的是,computed 這個函數在這里并不會立即執行,因為按照 Preact 的設計原則,computed signals 被規定為懶執行的(這個后面會介紹),它只有在本身值被讀取的時候才會觸發執行,同時它本身也是只可讀的:

console.log(c.value) // hello world

同時 computed signals 的值是會被緩存的。一般而言,computed(fn) 運行開銷會比較大, Preact 只會在真正需要的時候去重新更新它。一個正在執行的 computed(fn) 會追蹤它運行期間讀取到的那些 signals 值,如果這些值都沒變化,那么是會跳過重新計算的步驟的。

因此在上面的示例中,只要 s1.value 和 s2.value 的值不變化,那么 c.value 的值永遠不會重新計算。

同樣,一個 computed signal 也可以被其它的 computed signal 消費:

const count = signal(1);
const double = computed(() => count.value * 2);
const quadruple = computed(() => double.value * 2);

console.log(quadruple.value); // Console: 4
count.value = 20;
console.log(quadruple.value); // Console: 80

同時 computed 依賴的 signals 也并不需要是靜態的,它只會對最新的依賴變更發生重新執行:

const choice = signal(true);
const funk = signal("Uptown");
const purple = signal("Haze"); 

const c = computed( 
  () => {
    if (choice.value) {
      console.log(funk.value, "Funk");
    } else {
      console.log("Purple", purple.value);
    }
}); 
  
c.value; // Console: Uptown Funk

purple.value = "Rain"; // purple is not a dependency, so 
c.value; // effect doesn't run

choice.value = false; 
c.value; // Console: Purple Rain 

funk.value = "Da"; // funk not a dependency anymore, so 
c.value; // effect doesn't run

我們可以通過這個 Demo 看到,c 這個 computed signal 只會在它最新依賴的 signal 對象值發生變化的時候去觸發重新執行。

effect(fn)

上一節中介紹的 Computed Signals 一般都是一些不帶副作用的純函數(所以它們可以在初次懶執行)。這節要介紹的 Effect Signals 則是用來處理一些響應式中的副作用使用。

和 Computed Signals 一樣的是,Effect Signals 同樣也會對依賴進行追蹤。但 Effect 則不會懶執行,與之相反,它會在創建的時候立即執行,然后當它追蹤的依賴值發生變化的時候,它會隨著變化而更新:

import { signal, computed, effect } from '@preact/signals-core';

const count = signal(1);
const double = computed(() => count.value * 2);
const quadrple = computed(() => double.value * 2);

effect(() => {
  // is now 4
  console.log('quadruple is now', quadruple.value);
})

count.value = 20; // is now 80

這里的 effect 執行是由 Preact Signals 內部的通知機制觸發的。當一個普通的 signal 發生變化的時候,它會通知它的直接依賴項,這些依賴項同樣也會去通知它們自己對應的直接依賴項,依此類推。

在 Preact 的內部實現中,通知路徑中的 Computed Signals 會被標記為 OUTDATED 的狀態,然后再去做重新執行計算操作。如果一個依賴變更通知一直傳播到一個 effect 上面,那么這個 effect 會被安排到當其自身前面的 effect 函數執行完之后再執行。

如果你只想調用一次 effect 函數,那么可以把它賦值為一個函數調用,等到這個函數執行完,這個 effect 也會一起結束:

const count = signal(1);
const double = computed(() => count.value * 2);
const quadruple = computed(() => double.value * 2);
const dispose = effect(() => {
  console.log('quadruple is now', quadruple.value);
});

// Console: quadruple is now 4
dispose();
count.value = 20;

batch(fn)

用于將多個值的更新在回調結束時合成為一個。batch 的處理可以被嵌套,并且只有當最外層的處理回調完成后,更新才會刷新:

const name = signal('Dong');
const surname = signal('Zoom');

// Combine both writes into one
batch(() => {
  name.value = 'Haha';
  surname.value = 'Nana';
})

實現方式

在開始介紹之前,我們結合前面的 API 介紹,來強調一些 Preact Signals 本身的設計性原則:

  • 依賴追蹤: 跟蹤使用到的 signals(不管是 signals 還是 computed)。依賴項可能會動態改變
  • 懶執行的 computed: computed 值在被需要的時候運行
  • 緩存: computed 值只在依賴項可能改變的情況下才會重新計算
  • 立即執行的 effect: 當依賴中的某個內容變化時,effect 應該盡快運行。

關于 Signals 的具體實現方式具體可以參考: https://github.com/preactjs/signals 。

依賴追蹤

不管什么時候評估實現 compute / effect 這兩個函數,它們都需要一種在其運行時期捕獲他們會讀取到的 signal 的方式。Preact Signals 給 Compute 和 Effect 這兩個 Signals 都設置了其自身對應的 context 。

當讀取 Signal 的 .value 屬性時,它會調用一次 getter ,getter 會將 signal 當成當前 context 依賴項源頭給添加進來。這個 context 也會被這個 signal 添加為其依賴項目標。

到最后,signal 和 effects 對其自身的依賴關系以及依賴者都會有個最新的試圖。每個 signal 都可以在其 .value 值發生改變的時候通知到它的依賴者。例如在一個 effect 執行完成之后釋放掉了,effect 和 computed signals 都是可以通知他們依賴集去取消訂閱這些通知的。

圖片圖片

同一個 signals 可能在一個 context 里面被讀取多次。在這種情況下,進行依賴項的去重會很方便。然后我們還需要一種處理 發生變化依賴項集合 的方式: 要么在每次重新觸發運行時 時再重建依賴項集合,要么遞增地添加/刪除依賴項 / 依賴者。

Preact Signals 在早期版本中使用到了 JS 的 Set 對象去處理這種情況(Set 本身的性能比較不錯,能在 O(1) 時間內去添加 / 刪除子項,同時能在 O(N) 的時間里面遍歷當前集合,對于重復的依賴項,Set 也會自動去重)。

但創建 Sets 的開銷可能相對 Array 要更昂貴(從空間上看),因為 Signals 至少需要創建兩個單獨的 Sets : 存儲依賴項和依賴者。

圖片圖片

同時 Sets 中也有個屬性,它們是按照插入順序來進行迭代。這對于 Signals 中處理緩存的情況會很方便,但也有些情況下,Signals 插入的順序并不是總保持不變的,例如以下情況:

const s1 = signal(0)
const s2 = signal(0)
const s3 = signal(0)

const c = computed(() => {
  if (s1.value) {
    s2.value;
    s3.value
  } else {
    s3.value 
    s2.value
  }
})

可以看到,這這次代碼中,依賴項的順序取決于 s1 這個 signal,順序要么是 s1、s2、s3,要么是 s1、s3、s2。按照這種情況,就必須采取一些其他的步驟來保證 Sets 中的內容順序是正常的: 刪除然后再添加項目,清空函數運行前的集合,或者為每次運行創建一個新的集合。每種方法都有可能導致內存抖動。而所有這些只是為了處理理論上可能,但可能很少出現的,依賴關系順序改變的情況。

而 Preact Signals 則采用了一種類似雙向鏈表的數據結構去存儲解決了這個問題。

鏈表

鏈表是一種比較原始的存儲結構,但對于實現 Preact Signals 的一些特點來說,它具備一些非常好的屬性,例如在雙向鏈表節點中,以下操作會非常節省:

  • 在 O(1) 時間內,將一個 signals 值插到鏈表的某一端
  • 在 O(1) 時間內,刪除鏈表任何位置的一個節點(假設存在對應指針的情況下)
  • 在 O(n) 時間內,遍歷鏈表中的節點

以上這些操作,都可以用于管理 Signals 中的依賴 / 依賴列表。

Preact 會首先給每個依賴關系都創建一個 source Node 。而對應 Node 的 source 屬性會指向目前正在被依賴的 Signal。同時每個 Node 都有 nextSource 和 prevSource 屬性,分別指向依賴列表中的下一個和前一個 source Nodes 。Effect 和 Computed Signals 獲得一個指向鏈表第一個 Node 的 sources 屬性,然后我們可以去遍歷這里面的一些依賴關系,或者去插入 / 刪除新的依賴關系。

圖片圖片

然后處理完上面的依賴項步驟后,我們再反過來去做同樣的事情: 給每個依賴者創建一個 Target Node 。Node 的 target 屬性則會指向它們依賴的 Effect 或 Computed Signals。nextTarget 和 prevTarget 構建一個雙項鏈表。普通和 computed Signals Node 節點中會有個targets 屬性用于指向他們依賴列表中的第一個 Target Node:

圖片圖片

但一般依賴項和依賴者都是成對出現的。對于每個 source Node 都會有一個對應的 target Node 。本質上我們可以將 source Nodes 和 target Nodes 統一合并為 Nodes 。這樣每個 Node 本質上會有四條鏈節,依賴者可以作為它依賴列表的一部分使用,如下圖所示:

圖片圖片

在每個 computed / effect 函數執行之前,Preact 會迭代以前的依賴關系,并設置每個 Node 為 unused 的標志位。同時還會臨時把 Node 存儲到它的 .source.node 屬性中用于以后使用。

在函數執行期間,每次讀取依賴項時,我們可以使用節點以前記錄的值(上次的值)來發現該依賴項是否在這次或者上次運行時已經被記錄下來,如果記錄下來了,我們就可以回收它之前的 Node(具體方式就是將這個節點的位置重新排序)。如果是沒見過的依賴項,我們會創建一個新的 Node 節點,然后將剩下的節點按照使用的時期進行逆序排序。

函數運行結束后,Preact Signals 會遍歷依賴列表,將打上了 unused 標志的 Nodes 節點給刪除掉。然后整理一下剩余的鏈表節點。

這種鏈表結構可以讓每次只用給每個依賴項 - 依賴者的關系對分配一個 Node,然后只要依賴關系是存在的,這個節點是可以一直用的(不過需要更新下節點的順序而已)。如果項目的 Signals 依賴樹是穩定的,內存也會在構建完成后一直保持穩定。

立即執行的 effect

有了上面依賴追蹤的處理,通過變更通知實現的立即執行的 effect 會很容易。Signals 通知其依賴者們,自己的值發生了變化。如果依賴者本身是個有依賴者的 computed signals,那么它會繼續往前傳遞通知。依此類推,接到通知的 effect 會自己安排自己運行。

如果通知的接收端,已經被提前通知了,但還沒機會執行,那它就不會向前傳遞通知了。這會減輕當前依賴樹擴散出去或者進來時形成的通知踩踏。如果 signals 本身的值實際上沒發生變化,例如 s.value = s.value。普通的 signal 也不會去通知它的依賴者。

Effect 如果想調度它自身,需要有個排序好的調度表。Preact 給每個 Effect 實例都添加了專門的 .nextBatchedEffect 屬性,讓 Effect 實例作為單向調度列表中的節點進行雙重作用,這減少了內存抖動,因為反復調度同一個效果不需要額外的內存分配或釋放。

通知訂閱和垃圾回收

computed signals 實際上并不總是從他們的依賴關系中獲取通知的。只有當有像 effect 這樣的東西在監聽 signals 本身時,compute signals 才會訂閱依賴通知。這避免了下面的一些情況:

const s = signal(0);

{
  const c = computed(() => s.value)
}
// c 并不在同一個作用域下

如果 c 總是訂閱來自 s 的通知,那么 c 無法被垃圾回收,直到 s 也去它這個 scope 上面去。主要因為 s 會繼續掛在一個對 c 的引用上。

在 Preact Signals 中,鏈表提供了一種比較好的辦法去動態訂閱和取消訂閱依賴通知。

在那些 computed signal 已經訂閱了通知的情況下,我們可以利用這個做一些額外的優化。后面會介紹 computed 懶執行和緩存。

Computed signals 的懶執行 & 緩存

實現懶執行 computed Signals 的最簡單方法是每次讀取其值時都重新計算。不過,這不是很高效。這就是緩存和依賴跟蹤需要幫助優化的地方。

每個普通和 Computed Signals 都有它們自己的版本號。每次當其值變化時,它們會增加版本號。當運行一個 compute fn 時,它會在 Node 中存儲上次看到的依賴項的版本號。我們原本可以選擇在節點中存儲先前的依賴值而不是版本號。然而,由于 computed signals 是懶執行的,這些依賴值可能會永遠掛在一些過期或者無限循環執行的 Node 節點上。因此,我們認為版本編號是一種安全的折中方法。

我們得出了以下算法,用于確定當 computed signals 可以懶執行和復用它的緩存:

  1. 如果自上次運行以來,任何地方的 signal 的值都沒有改變,那么退出 & 返回緩存值。

每次當普通 signal 改變時,它也會遞增一個全局版本號,這個版本號在所有的普通信號之間共享。每個計算信號都跟蹤他們看到的最后一個全局版本號。如果全局版本自上次計算以來沒有改變,那么可以早點跳過重新計算。無論如何,在這種情況下,都不可能對任何計算值進行任何更改。

  1. 如果 computed signals 正在監聽通知,并且自上次運行以來沒有被通知,那么退出 & 返回緩存值。

當 compute signals 從其依賴項中得到通知時,它標記緩存值已經過時。如前所述,compute signals 并不總是得到通知。但是當他們得到通知時,我們可以利用它。

  1. 按順序重新評估依賴項。檢查它們的版本號。如果沒有依賴項改變過它的版本號,即使在重新評估后,也退出 & 返回緩存值。

這個步驟是我們特別關心保持依賴項按使用順序排列的原因。如果一個依賴項發生改變,那么我們不希望重更新 compute list 中后來的依賴項,因為那可能只是不必要的工作。誰知道,也許那個第一個依賴項的改變導致下次 compute function 運行時丟棄了后面的依賴項。

  1. 運行 compute function。如果返回的值與緩存值不同,那么遞增計算信號的版本號。緩存并返回新值。

這是最后的手段!但如果新值等于緩存的值,那么版本號不會改變,而線路下方的依賴項可以利用這一點來優化他們自己的緩存。

最后兩個步驟經常遞歸到依賴項中。這就是為什么早期的步驟被設計為嘗試短路遞歸的原因。

一些思考

JSX 渲染

Signal 在 Preact JSX 語法進行傳值的時候,可以直接傳對應的 Signal 對象而不是具體的值,這樣在 Signal 對象的值發生變化的時候,可以在組件不經過重新渲染的情況下觸發值的變化(本質上是把 Signal 值綁定到 DOM 值上)。

例如以下組件:

import { render } from 'preact'
import { signal } from '@preact/signals'

const count = signal(1);

// Component 跳過流程是怎么處理
// 可能對 state less 的組件跳過 render(function component)
funciton Counter() {
  console.log('render')
  return (
    <>
     <p>Count: {count}</p>
     <button notallow={() => count.value ++}>Add Count</button>
    </>
  )
}

render(<TodoList />, document.getElement('app'))

這個地方如果傳的是個 count 的 signal 對象,那么在點擊 button 的時候,這里的 Counter 組件并不會觸發 re-render ,如果是個 signal 值,那么它會觸發更新。

關于把 Signals 在 JSX 中渲染成文本值,可以直接參考: https://github.com/preactjs/signals/pull/147

這里渲染的原理是 Preact Signal 本身會去劫持原有的 Diff 執行算法:

圖片圖片

把對應的 signal value 存到 vnode.__np 這個節點屬性上面去,并且這里會跳過原有的 diff 算法執行邏輯(這里的 old(value) 執行函數)。

然后在 diff 完之后的更新的時候,直接去把對應的 signals 值更新到真實的 dom 節點上面去即可:

圖片圖片

Preact signals 和 hooks 之間關系

兩者并不互斥,可以一起使用,因為兩者所依賴的更新的邏輯不一樣。

Preact Signals 對比 Hooks 帶來收益

Preact Signals 本身在狀態管理上區別于 React Hooks 上的一個點在于: Signals 本身是基于應用的狀態圖去做數據更新,而 Hooks 本身則是依附于 React 的組件樹去進行更新。

本質上,一個應用的狀態圖比組件樹要淺很多,更新狀態圖造成的組件渲染遠遠低于更新狀態樹所產生的渲染性能損耗,具體差異可以參考分別使用 Hooks 和 Signals 的 Devtools Profile 分析:

圖片圖片

參考資料

  • Why Signals Are Better than Preact: https://www.youtube.com/watch?v=SO8lBVWF2Y8
  • https://preactjs.com/guide/v10/signals/

責任編輯:武曉燕 來源: zoomdong
相關推薦

2022-09-04 21:08:50

響應式設計Resize

2009-07-06 09:23:51

Servlet定義

2009-09-04 10:05:16

C#調用瀏覽器瀏覽器的原理

2014-08-26 09:40:54

圖數據數據挖掘

2020-08-05 08:21:41

Webpack

2009-08-27 14:29:28

顯式實現接口

2009-09-07 05:24:22

C#窗體繼承

2020-03-31 08:05:23

分布式開發技術

2017-07-19 11:11:40

CTS漏洞檢測原理淺析

2020-11-05 11:14:29

Docker底層原理

2018-10-25 15:13:23

APP脫殼工具

2023-05-11 07:25:57

ReduxMiddleware函數

2009-07-16 10:23:30

iBATIS工作原理

2009-08-24 10:37:27

C# 泛型

2009-08-13 18:36:36

C#繼承構造函數

2009-08-04 14:18:49

ASP.NET郵件列表

2021-06-10 08:29:15

Rollup工具前端

2022-03-17 08:55:43

本地線程變量共享全局變量

2025-05-27 01:00:00

2015-12-02 14:10:56

HTTP網絡協議代理原理
點贊
收藏

51CTO技術棧公眾號

日韩精品一区二区三区四区视频| xnxx国产精品| 欧美日韩国产成人| bl动漫在线观看| 欧美日韩五码| 亚洲人精品一区| 成人激情av在线| 五月天综合在线| 成人免费在线播放| 日韩欧美综合在线| 欧美成人精品欧美一级乱| 中文字幕在线视频区| 国产福利精品导航| 热re91久久精品国99热蜜臀| 一级性生活免费视频| 久久久亚洲欧洲日产| 欧美色国产精品| 黄色大片中文字幕| 黄网站app在线观看| 91视视频在线观看入口直接观看www | 国产一区欧美二区三区| 日本网站免费观看| 91精品国产成人观看| 亚洲精品在线视频| 亚洲成a人片在线www| 日韩一级特黄| 亚欧色一区w666天堂| 免费在线精品视频| h网站视频在线观看| 99国产精品久久久久久久久久| 亚洲sss综合天堂久久| 国产污视频网站| 亚洲成人中文| 欧美大学生性色视频| 三级影片在线观看| 精品一区二区三区在线| 日韩精品视频免费| 人妖粗暴刺激videos呻吟| 秋霞一区二区| 在线电影国产精品| 日本特黄a级片| 成人av观看| 午夜日韩在线观看| 国产精品免费看久久久无码| 欧美日韩欧美| 国产精品乱码妇女bbbb| 日本中文不卡| 国外av在线| 国产欧美日本一区二区三区| 欧美日韩精品久久| 日本啊v在线| 久久嫩草精品久久久精品一| 精品中文字幕一区| 亚洲欧美丝袜中文综合| 成人av电影在线网| 精品视频第一区| 五月激情婷婷网| 91美女蜜桃在线| 欧美日本韩国在线| 黄色大片在线看| 国产日韩欧美a| 亚洲国内在线| 日本在线视频观看| 亚洲欧美韩国综合色| 影音先锋成人资源网站| 日本大片在线播放| 亚洲一区二区成人在线观看| 国产av国片精品| 国产激情视频在线看| 天天做天天摸天天爽国产一区| www一区二区www免费| 亚洲精品成人图区| 欧美吞精做爰啪啪高潮| 91av视频免费观看| 99精品中文字幕在线不卡| 亚洲国产欧美一区二区丝袜黑人 | 欧洲中文字幕国产精品| 五月天激情四射| 免费观看一级特黄欧美大片| 91精品在线观| 亚洲爱爱综合网| 26uuu精品一区二区| 亚洲色图自拍| 久草在线视频网站| 色婷婷久久一区二区三区麻豆| 蜜桃免费在线视频| 欧美激情三级| 亚洲精品在线看| 91麻豆免费视频网站| 在线成人h网| 国产精品嫩草影院久久久| 国产按摩一区二区三区| 99精品国产99久久久久久白柏| 日韩区国产区| 美足av综合网| 欧美午夜精品一区二区蜜桃| 免费黄视频在线观看| 久久不见久久见国语| 久久91精品国产91久久跳| 天天操夜夜操视频| 国产一区二区三区美女| 蜜桃999成人看片在线观看| 亚洲免费视频一区二区三区| 亚洲国产精品自拍| 一级做a免费视频| 亚洲国产欧美日韩在线观看第一区 | 日韩精品无码一区二区三区久久久| 国产精品videosex性欧美| 97视频com| 91女人18毛片水多国产| 99re这里只有精品首页| 91看片淫黄大片91| 国产一区二区色噜噜| 亚洲精品久久久久久久久| 爱爱视频免费在线观看| 日韩电影在线免费看| 国产精品二区在线| 国产网站在线免费观看| 欧美自拍偷拍午夜视频| 国产精品久久不卡| 国内精品久久久久久久97牛牛| 国产精品久久久久久搜索| 五月天婷婷在线播放| 一片黄亚洲嫩模| 国产无色aaa| 手机在线一区二区三区| 国产精品成人av性教育| 色综合成人av| 婷婷综合另类小说色区| 亚洲成人精品在线播放| 亚洲经典一区| 91在线观看免费观看| 91官网在线| 欧美三级视频在线观看| 男人天堂av电影| 毛片一区二区| 奇米精品在线| 一呦二呦三呦精品国产| 亚洲欧美日韩国产中文| 日本天堂网在线| 91网站黄www| 玩弄中年熟妇正在播放| 2021年精品国产福利在线| 欧美成人免费全部| 国产精品羞羞答答在线| 成人欧美一区二区三区1314| wwwwwxxxx日本| 91视频一区| 91精品视频播放| 97caopron在线视频| 欧美一区二区三区在线观看 | 精品欧美激情精品一区| 精品视频站长推荐| 国产农村妇女精品一二区| 精品产品国产在线不卡| 神马久久午夜| 亚洲石原莉奈一区二区在线观看| 国产又粗又猛又爽又| 国产亚洲午夜高清国产拍精品| 十八禁视频网站在线观看| 国产探花在线精品| 成人在线中文字幕| 污的网站在线观看| 亚洲精品999| 69亚洲精品久久久蜜桃小说| 欧美国产乱子伦 | 蜜臀尤物一区二区三区直播| 亚洲国产精华液网站w| 91精品999| 欧美午夜一区| 欧美日韩国产精品一卡| 国产亚洲精彩久久| 欧美日韩高清在线观看| 亚洲人成色777777精品音频| 色哟哟一区二区| 97精品在线播放| 国产1区2区3区精品美女| 黄色一级片黄色| 国产成人1区| 成人在线播放av| 久久男人天堂| 国产一区二区三区视频| 国产suv一区二区| 欧美视频在线视频| 顶级黑人搡bbw搡bbbb搡| 国产99一区视频免费| 青青草原av在线播放| 欧美3p视频| 国产一区二区在线网站| 欧美日韩在线精品一区二区三区激情综合 | 亚洲女优在线观看| 国产麻豆精品一区二区| 成人免费aaa| 天天综合网网欲色| 久久久久久一区| 高清在线一区二区| 欧美一区二区三区免费观看| 久操视频在线| 亚洲欧美一区二区三区四区 | 中文字幕日韩欧美在线视频| 性一交一乱一透一a级| 91国产丝袜在线播放| 免费在线一级片| 国产精品天美传媒沈樵| 亚洲国产精品成人综合久久久| 久久成人羞羞网站| 你懂的av在线| 欧美三级第一页| 亚洲国产日韩欧美| 日韩黄色网络| 亚洲自拍av在线| 国产在线|日韩| 777777777亚洲妇女| 在线你懂的视频| 色偷偷综合社区| 免费在线黄色影片| 亚洲国产99精品国自产| 国产又黄又大又爽| 色狠狠av一区二区三区| www日韩精品| 亚洲午夜在线电影| 亚洲成人生活片| 亚洲欧洲日韩女同| 激情五月深爱五月| 国产亚洲综合在线| 精品无码人妻一区| 91在线视频官网| 精品国产免费久久久久久婷婷| 国产呦精品一区二区三区网站| 色婷婷狠狠18| 老色鬼久久亚洲一区二区| 国产亚洲欧美在线视频| 亚洲激情视频| 少妇人妻大乳在线视频| 国内精品久久久久久久影视蜜臀| 成人黄色片免费| 欧美激情亚洲| 国产精品一区在线免费观看| 亚洲天天影视网| 最新av在线免费观看| 日韩在线观看| 中文字幕人成一区| 久久精品久久久| 成人免费看片视频在线观看| 在线精品视频在线观看高清| 国产成人免费高清视频| 欧美激情视频一区二区三区免费| 日本丰满大乳奶| 欧美精品一线| 缅甸午夜性猛交xxxx| 国产精品一页| 免费黄色特级片| 免费观看日韩av| 天堂av2020| 国产成人av电影免费在线观看| 久久久久99人妻一区二区三区| 懂色中文一区二区在线播放| 日本不卡视频一区| 97久久精品人人做人人爽50路| 国产精品九九九九九| 国产丝袜欧美中文另类| 老司机深夜福利网站| 亚洲欧美乱综合| 精品无码免费视频| 欧美性极品xxxx做受| 久久久久久久久久一级| 欧美精品色一区二区三区| 国产黄色片免费观看| 亚洲国产成人久久综合一区| 嫩草研究院在线| 日韩一区二区av| 波多野结衣在线播放| 日本成人免费在线| 日韩大陆av| 国产精品免费一区二区| 精品国产一区二区三区香蕉沈先生 | 五月天丁香社区| 久久综合丝袜日本网| 18啪啪污污免费网站| 亚洲黄色小说网站| caoporn国产| 日韩一级完整毛片| 欧美日本韩国一区二区| 久久精品国产96久久久香蕉| segui88久久综合| 国产精品一区二区在线| 国产suv精品一区| 日韩中文字幕一区二区| 午夜精品久久久久99热蜜桃导演| 波多野结衣家庭教师在线播放| 久久91精品久久久久久秒播| 欧美肉大捧一进一出免费视频| 国产精品剧情在线亚洲| 日本午夜精品理论片a级app发布| 日本高清成人免费播放| 精品国产无码AV| 中文字幕日韩欧美| 亚洲天堂av在线| aaa级精品久久久国产片| 国内黄色精品| 亚洲国产成人精品无码区99| 精品影视av免费| 右手影院亚洲欧美| 亚洲一区二区精品久久av| 在线观看毛片av| 精品视频在线观看日韩| 色呦呦在线视频| 国产日韩欧美黄色| 精品一区在线| 欧美亚洲日本一区二区三区| 狠狠色综合日日| 亚洲一二三精品| 色综合久久中文字幕综合网| 亚洲精品18在线观看| 北条麻妃久久精品| 国产私拍福利精品视频二区| 九九99玖玖| 激情文学一区| 爱情岛论坛亚洲自拍| 国产精品你懂的在线欣赏| 精品人妻无码一区二区性色| 精品国产网站在线观看| 国产精品实拍| 成人h猎奇视频网站| 国内精品久久久久久久影视简单| 国产91在线免费| 波多野结衣一区二区三区| 久久久久久久久久久久久久久久久| 欧美日韩亚州综合| 99re在线视频| 国产精品免费久久久| 精品国产中文字幕第一页| 国产性xxxx18免费观看视频| 91原创在线视频| 日韩免费视频一区二区视频在线观看| 精品不卡在线视频| 国产啊啊啊视频在线观看| http;//www.99re视频| 欧美国产精品| 无码国产精品久久一区免费| 亚洲精品视频一区| 国产夫绿帽单男3p精品视频| 久久综合免费视频| 宅男噜噜噜66国产精品免费| 一区二区在线中文字幕电影视频| 麻豆精品视频在线| 黄色片网站在线播放| 欧美日本在线一区| 黄色免费在线看| 亚洲综合中文字幕在线| 欧美另类亚洲| 黄色网址在线视频| 一本色道亚洲精品aⅴ| 韩日在线视频| 国产色婷婷国产综合在线理论片a| 日韩精品一区二区三区免费观影 | 91国内精品久久| 欧美自拍视频| 人妻无码视频一区二区三区| 欧美高清在线精品一区| 一级做a爱片久久毛片| 米奇精品一区二区三区在线观看| 日韩免费一级| 免费看日本毛片| 国产视频一区二区在线观看| 亚洲天堂一二三| 欧美激情精品久久久久久久变态| 女同久久另类99精品国产| 欧美成人免费高清视频| 国产精品的网站| 国精产品一品二品国精品69xx| 68精品国产免费久久久久久婷婷| 国产一区二区三区四区五区传媒 | 日韩精品在线一区二区三区| 久久久成人av| 欧美日韩破处| 激情五月俺来也| 亚洲成人在线免费| jizz在线观看| 成人片在线免费看| 丝袜脚交一区二区| 久久中文免费视频| 日韩精品中文字幕有码专区| 国产69精品久久久久9999人| 国产精品国三级国产av| 久久久久成人黄色影片| 国产精品一二三四五区| 啪一啪鲁一鲁2019在线视频| 亚洲色图网站| 免费看污片的网站| 日韩精品中文字幕在线一区| 成人天堂yy6080亚洲高清| 免费观看国产视频在线| 久久亚洲欧美国产精品乐播| 国产免费福利视频| 青青草国产精品一区二区| 欧美1级日本1级| 丁香激情五月少妇| 欧美精品一区二区精品网| 免费成人高清在线视频|