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

一文帶你使用 Swift 實現 Promise

開發 前端
我最近在找如何使用 Swift 實現 Promise 的資料,因為沒找到好的文章,所以我想自己寫一篇。通過本文,我們將實現自己的 Promise 類型,以便明了其背后的邏輯。

[[421175]]

前言

我最近在找如何使用 Swift 實現 Promise 的資料,因為沒找到好的文章,所以我想自己寫一篇。通過本文,我們將實現自己的 Promise 類型,以便明了其背后的邏輯。

要注意這個實現完全不適合生產環境。例如,我們的 Promise 沒有提供任何錯誤機制,也沒有覆蓋線程相關的場景。我會在文章的后面提供一些有用的資源以及完整實現的鏈接,以饗愿深入挖掘的讀者。

注:為了讓本教程更有趣一點,我選擇使用 TDD 來進行介紹。我們會先寫測試,然后確保它們一個個通過。

第一個測試

先寫第一個測試:

  1. test(named: "0. Executor function is called immediately") { assert, done in 
  2.     var string: String = "" 
  3.     _ = Promise { string = "foo" } 
  4.     assert(string == "foo"
  5.     done() 

通過此測試,我們想實現:傳遞一個函數給 Promise 的初始化函數,并立即調用此函數。

注:我們沒有使用任何測試框架,僅僅使用一個自定義的test方法,它在 Playground 中模擬斷言(gist[1])。

當我們運行 Playground,編譯器會報錯:

  1. error: Promise.playground:41:9: error: use of unresolved identifier 'Promise' 
  2.     _ = Promise { string = "foo" } 
  3.         ^~~~~~~ 

合理,我們需要定義 Promise 類。

  1. class Promise { 
  2.  

再運行,錯誤變為:

  1. error: Promise.playground:44:17: error: argument passed to call that takes no arguments 
  2.     _ = Promise { string = "foo" } 
  3.                 ^~~~~~~~~~~~~~~~~~ 

我們必須定義一個初始化函數,它接受一個閉包作為參數。而且這個閉包應該被立即調用。

  1. class Promise { 
  2.  
  3.     init(executor: () -> Void) { 
  4.         executor() 
  5.     } 

由此,我們通過第一個測試。目前我們還沒有寫出什么值得夸耀的東西,但耐心一點,我們的實現將在下一節繼續增長。

  1. • Test 0. Executor function is called immediately passed  

我們先將此測試注釋掉,因為將來的 Promise 實現會變得有些不同。

最低限度

第二個測試如下:

  1. test(named: "1.1 Resolution handler is called when promise is resolved sync") { assert, done in 
  2.     let string: String = "foo" 
  3.     let promise = Promise<String> { resolve in 
  4.         resolve(string) 
  5.     } 
  6.     promise.then { (value: String) in 
  7.         assert(string == value) 
  8.         done() 
  9.     } 

這個測試挺簡單,但我們添加了一些新內容到 Promise 類。我們創建的這個 promise 有一個 resolution handler(即閉包的resolve參數),之后立即調用它(傳遞一個 value)。然后,我們使用 promise 的 then 方法來訪問 value 并用斷言確保其值。

在開始實現之前,我們需要引入另外一個不太一樣的測試。

  1. test(named: "1.2 Resolution handler is called when promise is resolved async") { assert, done in 
  2.     let string: String = "foo" 
  3.     let promise = Promise<String> { resolve in 
  4.         after(0.1) { 
  5.             resolve(string) 
  6.         } 
  7.     } 
  8.     promise.then { (value: String) in 
  9.         assert(string == value) 
  10.         done() 
  11.     } 

不同于測試 1.1,這里的resove方法被延遲調用。這意味著,在then里,value 不會立馬可用(因為 0.1 秒的延遲,調用then時,resolve還未被調用)。

我們開始理解這里的“問題”。我們必須處理異步。

我們的 promise 是一個狀態機。當它被創建時,promise 處于pending狀態。一旦resolve方法被調用(與一個 value),我們的 promise 將轉到resolved狀態,并存儲這個 value。

then方法可在任意時刻被調用,而不管 promise 的內部狀態(即不管 promise 是否已有一個 value)。當這個 promise 處于pending狀態時,我們調用then,value 將不可用,因此,我們需要存儲此回調。之后一旦 promise 變成resolved,我們就能使用 resolved value 來觸發同樣的回調。

現在我們對要實現的東西有了更好的理解,那就先以修復編譯器的報錯開始。

  1. error: Promise.playground:54:19: error: cannot specialize non-generic type 'Promise' 
  2.     let promise = Promise<String> { resolve in 
  3.                   ^      ~~~~~~~~ 

我們必須給Promise類型添加泛型。誠然,一個 promise 是這樣的東西:它關聯著一個預定義的類型,并能在被解決時,將一個此類型的 value 保留住。

  1. class Promise<Value> { 
  2.  
  3.     init(executor: () -> Void) { 
  4.         executor() 
  5.     } 

現在錯誤為:

  1. error: Promise.playground:54:37: error: contextual closure type '() -> Void' expects 0 arguments, but 1 was used in closure body 
  2.     let promise = Promise<String> { resolve in 
  3.                                     ^ 

我們必須提供一個resolve函數傳遞給初始化函數(即 executor)。

  1. class Promise<Value> { 
  2.  
  3.     init(executor: (_ resolve: (Value) -> Void) -> Void) { 
  4.         executor() 
  5.     } 

注意這個 resolve 參數是一個函數,它消耗一個 value:(Value) -> Void。一旦 value 被確定,這個函數將被外部世界調用。

編譯器依然不開心,因為我們需要提供一個resolve函數給executor。讓我們創建一個private的吧。

  1. class Promise<Value> { 
  2.  
  3.     init(executor: (_ resolve: @escaping (Value) -> Void) -> Void) { 
  4.         executor(resolve) 
  5.     } 
  6.  
  7.     private func resolve(_ value: Value) -> Void { 
  8.         // To implement 
  9.         // This will be called by the outside world when a value is determined 
  10.     } 

我們將在稍后實現resolve,當所有錯誤都被解決時。

下一個錯誤很簡單,方法then還未定義。

  1. error: Promise.playground:61:5: error: value of type 'Promise<String>' has no member 'then' 
  2.     promise.then { (value: String) in 
  3.     ^~~~~~~ ~~~~ 

讓我們修復之。

  1. class Promise<Value> { 
  2.  
  3.     init(executor: (_ resolve: @escaping (Value) -> Void) -> Void) { 
  4.         executor(resolve) 
  5.     } 
  6.  
  7.     func then(onResolved: @escaping (Value) -> Void) { 
  8.         // To implement 
  9.     } 
  10.  
  11.     private func resolve(_ value: Value) -> Void { 
  12.         // To implement 
  13.     } 

現在編譯器開心了,讓我們回到開始的地方。

我們之前說過一個Promise就是一個狀態機,它有一個pending狀態和一個resolved狀態。我們可以使用 enum 來定義它們。

  1. enum State<T> { 
  2.     case pending 
  3.     case resolved(T) 

Swift 的美妙讓我們可以直接存儲 promise 的 value 在 enum 中。

現在我們需要在Promise的實現中定義一個狀態,其默認值為.pending。我們還需要一個私有函數,它能在當前還處于.pending狀態時更新狀態。

  1. class Promise<Value> { 
  2.  
  3.     enum State<T> { 
  4.         case pending 
  5.         case resolved(T) 
  6.     } 
  7.  
  8.     private var state: State<Value> = .pending 
  9.  
  10.     init(executor: (_ resolve: @escaping (Value) -> Void) -> Void) { 
  11.         executor(resolve) 
  12.     } 
  13.  
  14.     func then(onResolved: @escaping (Value) -> Void) { 
  15.         // To implement 
  16.     } 
  17.  
  18.     private func resolve(_ value: Value) -> Void { 
  19.         // To implement 
  20.     } 
  21.  
  22.     private func updateState(to newState: State<Value>) { 
  23.         guard case .pending = state else { return } 
  24.         state = newState 
  25.     } 

注意updateState(to:)函數先檢查了當前處于.pending狀態。如果 promise 已經處于.resolved狀態,那它就不能再變成其他狀態了。

現在是時候在必要時更新 promise 的狀態,即,當resolve函數被外部世界傳遞 value 調用時。

  1. private func resolve(_ value: Value) -> Void { 
  2.     updateState(to: .resolved(value)) 

快好了,只缺少 then 方法還未實現。我們說過必須存儲回調,并在 promise 被解決時調用回調。這就來實現之。

  1. class Promise<Value> { 
  2.  
  3.     enum State<T> { 
  4.         case pending 
  5.         case resolved(T) 
  6.     } 
  7.  
  8.     private var state: State<Value> = .pending 
  9.     // we store the callback as an instance variable 
  10.     private var callback: ((Value) -> Void)? 
  11.  
  12.     init(executor: (_ resolve: @escaping (Value) -> Void) -> Void) { 
  13.         executor(resolve) 
  14.     } 
  15.  
  16.     func then(onResolved: @escaping (Value) -> Void) { 
  17.         // store the callback in all cases 
  18.         callback = onResolved 
  19.         // and trigger it if needed 
  20.         triggerCallbackIfResolved() 
  21.     } 
  22.  
  23.     private func resolve(_ value: Value) -> Void { 
  24.         updateState(to: .resolved(value)) 
  25.     } 
  26.  
  27.     private func updateState(to newState: State<Value>) { 
  28.         guard case .pending = state else { return } 
  29.         state = newState 
  30.         triggerCallbackIfResolved() 
  31.     } 
  32.  
  33.     private func triggerCallbackIfResolved() { 
  34.         // the callback can be triggered only if we have a value, 
  35.         // meaning the promise is resolved 
  36.         guard case let .resolved(value) = state else { return } 
  37.         callback?(value) 
  38.         callback = nil 
  39.     } 

我們定義了一個實例變量callback,以在 promise 處于.pending狀態時保留回調。同時我們創建一個方法triggerCallbackIfResolved,它先檢查狀態是否為.resolved,然后傳遞拆包的 value 給回調。這個方法在兩個地方被調用。一個是then方法中,如果 promise 已經在調用then時被解決。另一個在updateState方法中,因為那是 promise 更新其內部狀態從.pending到.resolved的地方。

有了這些修改,我們的測試就成功通過了。

  1. • Test 1.1 Resolution handler is called when promise is resolved sync passed (1 assertions) 
  2. • Test 1.2 Resolution handler is called when promise is resolved async passed (1 assertions) 

我們走對了路,但我們還需要做出一點改變,以得到一個真正的Promise實現。先來看看測試。

  1. test(named: "2.1 Promise supports many resolution handlers sync") { assert, done in 
  2.     let string: String = "foo" 
  3.     let promise = Promise<String> { resolve in 
  4.         resolve(string) 
  5.     } 
  6.     promise.then { value in 
  7.         assert(string == value) 
  8.     } 
  9.     promise.then { value in 
  10.         assert(string == value) 
  11.         done() 
  12.     } 
  1. test(named: "2.2 Promise supports many resolution handlers async") { assert, done in 
  2.     let string: String = "foo" 
  3.     let promise = Promise<String> { resolve in 
  4.         after(0.1) { 
  5.             resolve(string) 
  6.         } 
  7.     } 
  8.     promise.then { value in 
  9.         assert(string == value) 
  10.     } 
  11.     promise.then { value in 
  12.         assert(string == value) 
  13.         done() 
  14.     } 

這回我們對每個 promise 都調用了兩次then。

先看看測試輸出。

  1. • Test 2.1 Promise supports many resolution handlers sync passed (2 assertions) 
  2. • Test 2.2 Promise supports many resolution handlers async passed (1 assertions) 

雖然測試通過了,但你可能也注意問題。測試 2.2 只有一個斷言,但應該是兩個。

如果我們思考一下,這其實符合邏輯。誠然,在異步的測試 2.2 中,當第一個then被調用時,promise 還處于.pending狀態。如我們之前所見,我們存儲了第一次then的回調。但當我們第二次調用then時,promise 還是沒有被解決,依然處于.pending狀態,于是,我們將回調擦除換成了新的。只有第二個回調會在將來被執行,第一個被忘記了。這使得測試雖然通過,但只有一個斷言而不是兩個。

解決辦法也很簡單,就是存儲一個回調的數組,并在promise被解決時觸發它們。

讓我們更新一下。

  1. class Promise<Value> { 
  2.  
  3.     enum State<T> { 
  4.         case pending 
  5.         case resolved(T) 
  6.     } 
  7.  
  8.     private var state: State<Value> = .pending 
  9.     // We now store an array instead of a single function 
  10.     private var callbacks: [(Value) -> Void] = [] 
  11.  
  12.     init(executor: (_ resolve: @escaping (Value) -> Void) -> Void) { 
  13.         executor(resolve) 
  14.     } 
  15.  
  16.     func then(onResolved: @escaping (Value) -> Void) { 
  17.         callbacks.append(onResolved) 
  18.         triggerCallbacksIfResolved() 
  19.     } 
  20.  
  21.     private func resolve(_ value: Value) -> Void { 
  22.         updateState(to: .resolved(value)) 
  23.     } 
  24.  
  25.     private func updateState(to newState: State<Value>) { 
  26.         guard case .pending = state else { return } 
  27.         state = newState 
  28.         triggerCallbacksIfResolved() 
  29.     } 
  30.  
  31.     private func triggerCallbacksIfResolved() { 
  32.         guard case let .resolved(value) = state else { return } 
  33.         // We trigger all the callbacks 
  34.         callbacks.forEach { callback in callback(value) } 
  35.         callbacks.removeAll() 
  36.     } 

測試通過,而且都有兩個斷言。

  1. • Test 2.1 Promise supports many resolution handlers sync passed (2 assertions) 
  2. • Test 2.2 Promise supports many resolution handlers async passed (2 assertions) 

恭喜!我們已經創建了自己的Promise類。你已經可以使用它來抽象異步邏輯,但它還有限制。

注:如果從全局來看,我們知道then可以被重命名為observe。它的目的是消費 promise 被解決后的 value,但它不返回什么。這意味著我們暫時沒法串聯多個 promise。

串聯多個 Promise

如果我們不能串聯多個 promise,那我們的Promise實現就不算完整。

先來看看測試,它將幫助我們實現這個特性。

  1. test(named: "3. Resolution handlers can be chained") { assert, done in 
  2.     let string: String = "foo" 
  3.     let promise = Promise<String> { resolve in 
  4.         after(0.1) { 
  5.             resolve(string) 
  6.         } 
  7.     } 
  8.     promise 
  9.         .then { value in 
  10.             return Promise<String> { resolve in 
  11.                 after(0.1) { 
  12.                     resolve(value + value) 
  13.                 } 
  14.             } 
  15.         } 
  16.         .then { value in // the "observe" previously defined 
  17.             assert(string + string == value) 
  18.             done() 
  19.         } 

如測試所見,第一個then創建了一個有新 value 的新Promise并返回了它。第二個then(我們前一節定義的,被稱為observe)被串聯在后面,它訪問新的 value(其將是"foofoo")。

我們很快在終端里看到錯誤。

  1. error: Promise.playground:143:10: error: value of tuple type '()' has no member 'then' 
  2.         .then { value in 
  3.          ^ 

我們必須創建一個then的重載,它接受一個能返回 promise 的函數。為了能夠串聯調用then,這個方法必須也返回一個promise。這個then的原型如下。

  1. func then<NewValue>(onResolved: @escaping (Value) -> Promise<NewValue>) -> Promise<NewValue> { 
  2.     // to implement 

注:細心的讀者可能已經發現,我們在給Promise實現flatMap。就如給Optional和Array定義flatMap一樣,我們也可以給Promise定義它。

困難來了。讓我們一步步看看這個“flatMap”的then要怎么實現。

  • 我們需要返回一個Promise
  • 誰給我們這樣一個 promise?onResolved 方法
  • 但onResolved 需要一個類型為Value的 value 為參數。我們該怎樣得到這個 value? 我們可以使用之前定義的then(或者說 “observe”) 來在其可用時訪問它

如果寫成代碼,大概如下:

  1. func then<NewValue>(onResolved: @escaping (Value) -> Promise<NewValue>) -> Promise<NewValue> { 
  2.     then { value in // the "observe" one 
  3.         let promise = onResolved(value) // `promise` is a Promise<NewValue> 
  4.         // problem: how do we return `promise` to the outside ?? 
  5.     } 
  6.     return // ??!! 

就快好了。但我們還有個小問題需要修復:這個promise變量被傳遞給then的閉包所限制。我們不能將其作為函數的返回值。

我們要使用的技巧是創建一個包裝Promise,它將執行我們目前所寫的代碼,然后在promise變量解決時被同時解決。換句話說,當onResolved方法提供的 promise 被解決并從外部得到一個值,那包裝的 promise 也就被解決并得到同樣的值。

可能文字有些抽象,但如果我們寫成代碼,將看得更清楚:

  1. func then<NewValue>(onResolved: @escaping (Value) -> Promise<NewValue>) -> Promise<NewValue> { 
  2.     // We have to return a promise, so let's return a new one 
  3.     return Promise<NewValue> { resolve in 
  4.         // this is called immediately as seen in test 0. 
  5.         then { value in // the "observe" one 
  6.             let promise = onResolved(value) // `promise` is a Promise<NewValue> 
  7.             // `promise` has the same type of the Promise wrapper 
  8.             // we can make the wrapper resolves when the `promise` resolves 
  9.             // and gets a value 
  10.             promise.then { value in resolve(value) } 
  11.         } 
  12.     } 

如果我們整理一下代碼,我們將有這樣兩個方法:

  1. // observe 
  2. func then(onResolved: @escaping (Value) -> Void) { 
  3.     callbacks.append(onResolved) 
  4.     triggerCallbacksIfResolved() 
  5.  
  6. // flatMap 
  7. func then<NewValue>(onResolved: @escaping (Value) -> Promise<NewValue>) -> Promise<NewValue> { 
  8.     return Promise<NewValue> { resolve in 
  9.         then { value in 
  10.             onResolved(value).then(onResolved: resolve) 
  11.         } 
  12.     } 

最后,測試通過。

  1. • Test 3. Resolution handlers can be chained passed (1 assertions) 

串聯多個 value

如果你能給某個類型實現flatMap,那你就能利用flatMap為其實現map。對于我們的Promise來說,map該是什么樣子?

我們將使用如下測試:

  1. test(named: "4. Chaining works with non promise return values") { assert, done in 
  2.     let string: String = "foo" 
  3.     let promise = Promise<String> { resolve in 
  4.         after(0.1) { 
  5.             resolve(string) 
  6.         } 
  7.     } 
  8.     promise 
  9.         .then { value -> String in 
  10.             return value + value 
  11.         } 
  12.         .then { value in // the "observe" then 
  13.             assert(string + string == value) 
  14.             done() 
  15.         } 

注意第一個then沒有再返回一個Promise,而是將其接收的值做了一個變換。這個新的then就對應于我們想添加的map。

編譯器報錯說我們必須實現此方法。

  1. error: Promise.playground:174:26: error: declared closure result 'String' is incompatible with contextual type 'Void' 
  2.         .then { value -> String in 
  3.                          ^~~~~~ 
  4.                          Void 

這個方法很接近flatMap,唯一的不同是其參數onResolved函數返回一個NewValue而不是Promise

  1. // map 
  2. func then<NewValue>(onResolved: @escaping (Value) -> NewValue) -> Promise<NewValue> { 
  3.     // to implement 

之前我們說可以利用flatMap實現map。在我們的情況里,我們看到我們需要返回一個Promise。如果我們使用這個“flatMap”的then,并創建一個promise,再以映射后的 value 來直接解決,我們就搞定了。讓我來證明之。

  1. // map 
  2. func then<NewValue>(onResolved: @escaping (Value) -> NewValue) -> Promise<NewValue> { 
  3.     return then { value in // the "flatMap" defined before 
  4.         // must return a Promise<NewValue> here 
  5.         // this promise directly resolves with the mapped value 
  6.         return Promise<NewValue> { resolve in 
  7.             let newValue = onResolved(value) 
  8.             resolve(newValue) 
  9.         } 
  10.     } 

再一次,測試通過。

  1. • Test 4. Chaining works with non promise return values passed (1 assertions) 

如果我們移除注釋,再看看我們做出了什么。我們有三個then方法的實現,能被使用或串聯。

  1. // observe 
  2. func then(onResolved: @escaping (Value) -> Void) { 
  3.     callbacks.append(onResolved) 
  4.     triggerCallbacksIfResolved() 
  5.  
  6. // flatMap 
  7. func then<NewValue>(onResolved: @escaping (Value) -> Promise<NewValue>) -> Promise<NewValue> { 
  8.     return Promise<NewValue> { resolve in 
  9.         then { value in 
  10.             onResolved(value).then(onResolved: resolve) 
  11.         } 
  12.     } 
  13.  
  14. // map 
  15. func then<NewValue>(onResolved: @escaping (Value) -> NewValue) -> Promise<NewValue> { 
  16.     return then { value in 
  17.         return Promise<NewValue> { resolve in 
  18.             resolve(onResolved(value)) 
  19.         } 
  20.     } 

使用示例

實現告一段落。我們的Promise類已足夠完整來展示我們能夠用它做什么。

假設我們的app有一些用戶,結構如下:

  1. struct User { 
  2.     let id: Int 
  3.     let name: String 

假設我們還有兩個方法,一個獲取用戶id列表,另一個使用id獲取某個用戶。而且假設我們想顯示第一個用戶的名字。

通過我們的實現,我們可以這樣做,使用之前定義的這三個then。

  1. func fetchIds() -> Promise<[Int]> { 
  2.     ... 
  3.  
  4. func fetchUser(id: Int) -> Promise<User> { 
  5.     ... 
  6.  
  7. fetchIds() 
  8.     .then { ids in // flatMap 
  9.         return fetchUser(id: ids[0]) 
  10.     } 
  11.     .then { user in // map 
  12.         return user.name 
  13.     } 
  14.     .then { name in // observe 
  15.         print(name
  16.     } 

代碼變得十分易讀、簡潔,而且沒有嵌套。

結論本文結束,希望你喜歡它。

參考資料

[1]gist:

https://gist.github.com/felginep/039ca3b21e4f0cabb1c06126d9164680

[2]Promises in Swift by Khanlou:

http://khanlou.com/2016/08/promises-in-swift/

[3]JavaScript Promises … In Wicked Detail:

https://www.mattgreer.org/articles/promises-in-wicked-detail/

[4]PromiseKit 6 Release Details:

https://promisekit.org/news/2018/02/PromiseKit-6.0-Released/

[5]TDD Implementation of Promises in JavaScript:

https://www.youtube.com/watch?v=C3kUMPtt4hY

[6]Implementing Promises in Swift:

https://felginep.github.io/2019-01-06/implementing-promises-in-swift

本文轉載自微信公眾號「Swift社區」

 

責任編輯:姜華 來源: Swift社區
相關推薦

2023-11-20 08:18:49

Netty服務器

2022-12-20 07:39:46

2023-12-21 17:11:21

Containerd管理工具命令行

2023-07-31 08:18:50

Docker參數容器

2021-05-29 10:11:00

Kafa數據業務

2022-11-11 19:09:13

架構

2023-11-06 08:16:19

APM系統運維

2022-07-18 21:53:46

RocketMQ廣播消息

2024-10-10 09:12:10

Spring接口初始化

2023-10-27 08:15:45

2023-11-08 08:15:48

服務監控Zipkin

2022-02-24 07:34:10

SSL協議加密

2022-05-16 10:49:28

網絡協議數據

2023-03-06 21:29:41

mmap技術操作系統

2022-04-08 09:01:14

CSS自定義屬性前端

2020-11-27 09:40:53

Rollup前端代碼

2021-09-13 22:34:56

區塊鏈新基建數字化轉型

2019-06-13 21:31:19

AI

2024-05-22 09:45:49

2022-02-28 12:07:56

RxJS函數式
點贊
收藏

51CTO技術棧公眾號

国产精品99久久久久久久女警 | 欧美黑人xxx| 亚洲日本黄色片| av在线免费网址| 99在线视频精品| 国产精彩精品视频| 男人操女人的视频网站| 日韩高清在线免费观看| 欧美日韩视频在线第一区| 无码人妻精品一区二区三区99v| 后进极品白嫩翘臀在线视频| 久久久久国产精品午夜一区| 欧美成aaa人片免费看| 国产乱了高清露脸对白| 欧美另类激情| 欧美日韩国产中字| 精品国产无码在线| 日本一二三区在线视频| 经典一区二区三区| 欧美性资源免费| 欧美日韩午夜视频| 久久99国产成人小视频| 欧美mv日韩mv| 天天色综合社区| 欧美男人天堂| 怡红院av一区二区三区| 三区精品视频| 天天操天天干天天干| 久久99精品国产.久久久久久| 69av视频在线播放| 69av.com| 91日韩欧美| 亚洲欧美一区二区三区久久| 精品伦一区二区三区| 欧美视频免费看| 91成人免费网站| 欧美 日韩 激情| 国产精品偷拍| 亚洲欧美aⅴ...| 午夜精品一区二区在线观看的 | 在线视频不卡一区二区三区| 日韩欧美亚洲系列| 91在线视频免费91| 国产精品视频500部| 国产精品久久久久久久久久久久久久久久久久| 欧美一级播放| 97香蕉久久夜色精品国产| 欧美国产日韩在线观看成人| 久久亚洲专区| 日韩在线视频线视频免费网站| 免费a级黄色片| 日本一道高清一区二区三区| 欧美草草影院在线视频| 日韩精品在线播放视频| **国产精品| 在线播放欧美女士性生活| 成 人 黄 色 小说网站 s色| 国产精品美女午夜爽爽| 欧美日韩国产一区二区三区地区| 黄色三级视频片| 日韩成人高清| 精品视频在线免费| 午夜精品中文字幕| 91麻豆精品一二三区在线| 欧美猛男男办公室激情| 色婷婷.com| 亚洲精品大全| 日韩精品专区在线| 国产精品熟妇一区二区三区四区| 成人免费在线电影网| 亚洲黄页网在线观看| 国产又爽又黄无码无遮挡在线观看| 欧美wwwsss9999| 国产午夜精品久久久| 波多野结衣一本| 欧美精品一区二区三区中文字幕| 中文字幕亚洲无线码a| 登山的目的在线| 狠狠入ady亚洲精品经典电影| 国语自产精品视频在线看一大j8| 日韩精品手机在线| 日本系列欧美系列| 成人亲热视频网站| 国产av一区二区三区精品| 成人激情动漫在线观看| 久久综合一区二区三区| 国产高清一级毛片在线不卡| 中文字幕一区二区在线观看| 在线观看av的网址| 国产福利片在线观看| 日本韩国欧美在线| 五月天视频在线观看| 国产精伦一区二区三区| 亚洲色图综合网| 久艹在线观看视频| 999亚洲国产精| 国产精品在线看| 亚洲av色香蕉一区二区三区| 2019国产精品| 糖心vlog在线免费观看| 神马久久午夜| 91精品国产欧美一区二区| 水蜜桃av无码| 亚洲成av人片乱码色午夜| 91精品国产高清久久久久久91| 中文字幕第315页| 成人小视频免费在线观看| 日本在线播放一区| 九色91在线| 欧美日韩一区中文字幕| 稀缺小u女呦精品呦| 成人嘿咻视频免费看| 久久久欧美一区二区| 在线观看国产小视频| 成人av手机在线观看| 亚洲日本理论电影| 色吧亚洲日本| 日韩免费福利电影在线观看| 夜夜春很很躁夜夜躁| 亚洲国产高清一区二区三区| 国产精品丝袜视频| 日韩一区二区三区中文字幕| 亚洲综合自拍偷拍| 久热在线视频观看| 美女亚洲一区| 韩国美女主播一区| 99久久精品国产成人一区二区 | 在线不卡日本v二区707| 日本大香伊一区二区三区| 国产麻豆剧传媒精品国产av| 亚洲精彩视频| 91精品久久久久久久久久久| 加勒比一区二区三区在线| 亚洲国产一区在线观看| 欧美一区二区三区影院| 色欧美自拍视频| 国产成人精品免费视频| 欧美亚洲日本| 婷婷综合久久一区二区三区| 四虎精品一区二区| 欧美片第1页综合| 亚洲精品免费av| 欧美激情午夜| 91精品在线麻豆| 永久免费看mv网站入口| 久久99蜜桃精品| 亚洲一区二区免费视频软件合集| 日韩精品三区| 国产亚洲欧洲在线| 91麻豆精品在线| 国产欧美日韩激情| 99re精彩视频| 婷婷激情图片久久| 成人午夜高潮视频| 国产在线二区| 91精品国产高清一区二区三区 | 国产性生活一级片| 香蕉综合视频| 91成人理论电影| 韩国成人免费视频| 亚洲国产日韩精品在线| 久久亚洲精品国产| 久久久精品免费观看| 久久精品午夜福利| 日本一区二区高清不卡| 成人黄色免费在线观看| 9191在线播放| 亚洲福利在线看| 日韩av在线天堂| 久久综合九色综合97婷婷| 日本va中文字幕| 久久国产影院| 91超碰在线免费观看| 波多野结衣中文在线| 亚洲黄页网在线观看| 久久久久久久亚洲| 中文字幕一区二区三区不卡| 中文字幕av一区二区三区人妻少妇 | 欧美一区二区黄色| 日韩xxx高潮hd| 久久久久久亚洲综合| 高清av免费看| 红桃视频国产一区| 欧美一区二区三区在线免费观看| 国产黄色一区| 久久99精品久久久久久琪琪| 国产又爽又黄网站亚洲视频123| 在线国产电影不卡| 日本妇女毛茸茸| 91碰在线视频| 亚洲色图偷拍视频| 在线欧美不卡| 亚洲高清在线播放| 狠狠一区二区三区| 国产精品国产三级国产aⅴ浪潮| 国产超级va在线视频| 亚洲高清色综合| 在线免费看毛片| 午夜精品视频一区| 亚洲国产精品一区二区久久hs| 高潮精品一区videoshd| 97在线播放视频| 欧美喷水视频| 一级做a爰片久久| 麻豆精品99| 91丝袜美腿美女视频网站| 小h片在线观看| 久久亚洲综合国产精品99麻豆精品福利| 黑人乱码一区二区三区av| 欧美三级电影一区| 天海翼一区二区| 玉米视频成人免费看| 国产毛片欧美毛片久久久| www.亚洲免费av| www激情五月| 日韩成人一级片| 国产 日韩 欧美在线| 亚洲最新色图| 亚洲精品久久久久久一区二区| 国产精品白丝一区二区三区| 亚洲一区二区三区777| 国产日韩另类视频一区| 高清欧美性猛交xxxx| 国产剧情在线| 中文字幕日本欧美| 黄色国产在线| 日韩福利视频在线观看| 丰满熟妇人妻中文字幕| 91精品免费观看| 亚洲午夜无码久久久久| 欧美性开放视频| 日韩经典在线观看| 一区二区三区四区视频精品免费| 成人一级黄色大片| 国产精品乱人伦中文| 国产免费无遮挡吸奶头视频| 91亚洲男人天堂| 少妇搡bbbb搡bbb搡打电话| 国内精品国产三级国产a久久| 麻豆一区二区三区视频| 天堂精品中文字幕在线| 日韩av资源在线| 国产欧美激情| 精品视频免费在线播放| 亚洲精品美女91| 日本精品久久久久久久久久| 国内精品99| 成人黄色大片网站| 国产综合视频| 久久综合久久网| 99热在线精品观看| 337p粉嫩大胆噜噜噜鲁| 国产精品社区| 99999精品视频| 久久一二三四| 九色porny自拍| 狠狠色丁香婷婷综合久久片| 日日干日日操日日射| 国内精品伊人久久久久av一坑| 日韩欧美理论片| 国产999精品久久久久久绿帽| 日韩女优在线视频| 波多野结衣中文字幕一区二区三区| 国产视频精品视频| 久久嫩草精品久久久精品一| 亚洲观看黄色网| 国产午夜精品久久久久久免费视| 日韩av片在线| 中文字幕一区二区三区乱码在线| 福利所第一导航| 欧美日韩激情美女| japanese国产在线观看| 欧美日韩精品专区| 精品国产伦一区二区三区| 亚洲国产成人在线播放| 欧美777四色影视在线| 中文字幕欧美日韩| 欧美野外wwwxxx| 欧美亚洲视频在线观看| 超碰这里只有精品| 91亚洲国产成人久久精品网站| 亚洲国产一区二区三区网站| 久久精品国产精品国产精品污 | 二吊插入一穴一区二区| 国产精品电影网站| 欧美午夜网站| 蜜桃999成人看片在线观看| 青青草91久久久久久久久| 国产日韩欧美大片| 性xx色xx综合久久久xx| 男女污污视频网站| 91美女片黄在线观看91美女| 国产黄a三级三级| 精品久久久久久久久国产字幕| 中文无码av一区二区三区| 日韩女优av电影在线观看| 久草福利在线视频| 久久99青青精品免费观看| 偷拍视频一区二区三区| 亚洲xxx自由成熟| 久久99影视| 国产欧美自拍视频| 亚洲一区欧美二区| 老司机久久精品| 久久这里只有精品6| 综合五月激情网| 欧美性生活大片视频| 色噜噜在线播放| 久久影视电视剧免费网站清宫辞电视 | 久草视频国产在线| 九色|91porny| 精品无码人妻一区| 亚洲一区二区美女| 一级做a爱片性色毛片| 日韩经典第一页| 在线观看中文字幕的网站| 国产美女主播一区| 蜜臀久久99精品久久一区二区| 日韩在线视频在线| 久久99精品久久久久久| 久久亚洲无码视频| 都市激情亚洲色图| 亚洲精品网站在线| 久久中文字幕一区| 国产激情欧美| 日韩三级电影网站| 亚洲在线一区| 最新在线黄色网址| 亚洲高清中文字幕| www.国产麻豆| 美女av一区二区| 日韩黄色碟片| 亚洲精品美女久久7777777| 久久久天天操| 黄瓜视频污在线观看| 午夜精品123| 日韩中文字幕免费观看| 欧美激情综合色| 日韩一区二区三区高清在线观看| 青少年xxxxx性开放hg| 久久国产免费看| 久久精品国产亚洲AV成人婷婷| 在线精品观看国产| 国产经典自拍视频在线观看| 日韩av电影中文字幕| 日韩激情毛片| 久久精品一区二| 久久精品欧美日韩精品| 无码一区二区三区| 国产亚洲精品久久久| 秋霞国产精品| 亚洲欧美丝袜| 精品亚洲国产成人av制服丝袜 | 欧美亚洲视频在线看网址| 欧美一区二区三区红桃小说| www黄色日本| 26uuu国产在线精品一区二区| 啦啦啦免费高清视频在线观看| 亚洲美女性视频| 校园春色亚洲色图| 性欧美大战久久久久久久免费观看| 蜜臀av一区二区| 欧美成人手机视频| 亚洲成人网在线观看| 日韩激情电影| 亚洲va韩国va欧美va精四季| 老司机一区二区| 欧美激情精品久久| 精品国产乱码久久久久久1区2区| 爱啪啪综合导航| 日本一区二区三区视频免费看| 久久99精品国产.久久久久| 国产又黄又爽又无遮挡| 亚洲精品99久久久久中文字幕| 欧美黑人疯狂性受xxxxx野外| 亚洲一区二区三区乱码| 国产一区二区三区综合| 日本熟女一区二区| 亚洲天堂成人在线| 欧美一区二区三区婷婷| 91免费版看片| 久久久国产精品不卡| 亚洲视频一区二区三区四区| 欧美激情日韩图片| 杨幂一区二区三区免费看视频| 五月天视频在线观看| 欧美日韩国产丝袜另类| 99青草视频在线播放视| 99中文字幕| 三级欧美在线一区| 欧美卡一卡二卡三| 亚洲美女久久久| 激情视频亚洲| 老司机午夜av| 亚洲影院久久精品| 国产三级电影在线| 国产高清一区视频| 免费在线成人网| 国产免费av一区二区| 久久九九亚洲综合|