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

一次弄懂 Event Loop(徹底解決此類面試問題)

開發
Event Loop即事件循環,是指瀏覽器或 Node 的一種解決javaScript單線程運行時不會阻塞的一種機制,也就是我們經常使用異步的原理。

[[344363]]

 為啥要弄懂 Event Loop

  • 是要增加自己技術的深度,也就是懂得 JavaScript 的運行機制。
  • 現在在前端領域各種技術層出不窮,掌握底層原理,可以讓自己以不變,應萬變。
  • 應對各大互聯網公司的面試,懂其原理,題目任其發揮。

堆,棧、隊列

堆(Heap)
堆是一種數據結構,是利用完全二叉樹維護的一組數據,堆分為兩種,一種為最大堆,一種為最小堆,將根節點最大的堆叫做最大堆或大根堆,根節點最小的堆叫做最小堆或小根堆。堆是線性數據結構,相當于一維數組,有唯一后繼。

如最大堆

棧(Stack)
棧在計算機科學中是限定僅在表尾進行插入或刪除操作的線性表。棧是一種數據結構,它按照后進先出的原則存儲數據,先進入的數據被壓入棧底,最后的數據在棧頂,需要讀數據的時候從棧頂開始彈出數據。

棧是只能在某一端插入和刪除的特殊線性表。

隊列(Queue)
特殊之處在于它只允許在表的前端(front)進行刪除操作,而在表的后端(rear)進行插入操作,和棧一樣,隊列是一種操作受限制的線性表。

進行插入操作的端稱為隊尾,進行刪除操作的端稱為隊頭。隊列中沒有元素時,稱為空隊列。

隊列的數據元素又稱為隊列元素。在隊列中插入一個隊列元素稱為入隊,從隊列中刪除一個隊列元素稱為出隊。因為隊列只允許在一端插入,在另一端刪除,所以只有最早進入隊列的元素才能最先從隊列中刪除,故隊列又稱為先進先出(FIFO—first in first out)

Event Loop
在 JavaScript 中,任務被分為兩種,一種宏任務(MacroTask)也叫 Task,一種叫微任務(MicroTask)。

MacroTask(宏任務)
script 全部代碼、setTimeout、setInterval、setImmediate(瀏覽器暫時不支持,只有 IE10 支持,具體可見 MDN)、I/O、UI Rendering。

MicroTask(微任務)
Process.nextTick(Node 獨有)、Promise、Object.observe(廢棄)、MutationObserver(具體使用方式查看這里[1])

瀏覽器中的 Event Loop[2]
Javascript 有一個 main thread 主線程和 call-stack 調用棧(執行棧),所有的任務都會被放到調用棧等待主線程執行。

JS 調用棧
JS 調用棧采用的是后進先出的規則,當函數執行的時候,會被添加到棧的頂部,當執行棧執行完成后,就會從棧頂移出,直到棧內被清空。

同步任務和異步任務
Javascript 單線程任務被分為同步任務和異步任務,同步任務會在調用棧中按照順序等待主線程依次執行,異步任務會在異步任務有了結果后,將注冊的回調函數放入任務隊列中等待主線程空閑的時候(調用棧被清空),被讀取到棧內等待主線程的執行。

任務隊列 Task Queue,即隊列,是一種先進先出的一種數據結構。

事件循環的進程模型[3]

  • 選擇當前要執行的任務隊列,選擇任務隊列中最先進入的任務,如果任務隊列為空即 null,則執行跳轉到微任務(MicroTask)的執行步驟。
  • 將事件循環中的任務設置為已選擇任務。
  • 執行任務。
  • 將事件循環中當前運行任務設置為 null。
  • 將已經運行完成的任務從任務隊列中刪除。
  • microtasks 步驟:進入 microtask 檢查點。
  • 更新界面渲染。
  • 返回第一步。

執行進入 microtask 檢查點時,用戶代理會執行以下步驟:

  • 設置 microtask 檢查點標志為 true。
  • 當事件循環 microtask 執行不為空時:選擇一個最先進入的 microtask 隊列的 microtask,將事件循環的 microtask 設置為已選擇的 microtask,運行 microtask,將已經執行完成的 microtask 為 null,移出 microtask 中的 microtask。
  • 清理 IndexDB 事務
  • 設置進入 microtask 檢查點的標志為 false。

上述可能不太好理解,下圖是我做的一張圖片。

執行棧在執行完同步任務后,查看執行棧是否為空,如果執行棧為空,就會去檢查微任務(microTask) 隊列是否為空,如果為空的話,就執行 Task(宏任務),否則就一次性執行完所有微任務。

每次單個宏任務執行完畢后,檢查微任務(microTask)隊列是否為空,如果不為空的話,會按照先入先出的規則全部執行完微任務(microTask)后,設置微任務(microTask)隊列為 null,然后再執行宏任務,如此循環。

舉個例子

  1. console.log('script start'); 
  2.  
  3. setTimeout(function() { 
  4. console.log('setTimeout'); 
  5. }, 0); 
  6.  
  7. Promise.resolve().then(function() { 
  8. console.log('promise1'); 
  9. }).then(function() { 
  10. console.log('promise2'); 
  11. }); 
  12. console.log('script end'); 

首先我們劃分幾個分類:

第一次執行:

  1. Tasks:run script、 setTimeout callback 
  2.  
  3. Microtasks:Promise then 
  4.  
  5. JS stack: script 
  6. Log: script start、script end。 

執行同步代碼,將宏任務(Tasks)和微任務(Microtasks)劃分到各自隊列中。

第二次執行:

  1. Tasks:run script、 setTimeout callback 
  2.  
  3. Microtasks:Promise2 then 
  4.  
  5. JS stack: Promise2 callback 
  6. Log: script start、script end、promise1、promise2 

執行宏任務后,檢測到微任務(Microtasks)隊列中不為空,執行 Promise1,執行完成 Promise1 后,調用 Promise2.then,放入微任務(Microtasks)隊列中,再執行 Promise2.then。

第三次執行:

  1. Tasks:setTimeout callback 
  2.  
  3. Microtasks: 
  4.  
  5. JS stack: setTimeout callback 
  6. Log: script start、script end、promise1、promise2、setTimeout 

當微任務(Microtasks)隊列中為空時,執行宏任務(Tasks),執行 setTimeout callback,打印日志。

第四次執行:

  1. Tasks:setTimeout callback 
  2.  
  3. Microtasks: 
  4.  
  5. JS stack: 
  6. Log: script start、script end、promise1、promise2、setTimeout 

清空 Tasks 隊列和 JS stack。

以上執行幀動畫可以查看 Tasks, microtasks, queues and schedules[4]

或許這張圖也更好理解些。

再舉個例子

  1. console.log('script start'
  2.  
  3. async function async1() { 
  4. await async2() 
  5. console.log('async1 end'
  6. async function async2() { 
  7. console.log('async2 end'
  8. async1() 
  9.  
  10. setTimeout(function() { 
  11. console.log('setTimeout'
  12. }, 0) 
  13.  
  14. new Promise(resolve => { 
  15. console.log('Promise'
  16. resolve() 
  17. }) 
  18. .then(function() { 
  19. console.log('promise1'
  20. }) 
  21. .then(function() { 
  22. console.log('promise2'
  23. }) 
  24.  
  25. console.log('script end'

這里需要先理解 async/await。

async/await 在底層轉換成了 promise 和 then 回調函數。也就是說,這是 promise 的語法糖。每次我們使用 await, 解釋器都創建一個 promise 對象,然后把剩下的async函數中的操作放到 then 回調函數中。async/await 的實現,離不開 Promise。從字面意思來理解,async 是“異步”的簡寫,而 await 是 async wait 的簡寫可以認為是等待異步方法執行完成。

關于 73 以下版本和 73 版本的區別
在老版本版本以下,先執行 promise1 和 promise2,再執行 async1。在 73 版本,先執行 async1 再執行promise1和 promise2。主要原因是因為在谷歌(金絲雀)73 版本中更改了規范,如下圖所示:

區別在于 RESOLVE(thenable)和之間的區別 Promise.resolve(thenable)。

在老版本中

  • 首先,傳遞給 await 的值被包裹在一個 Promise 中。然后,處理程序附加到這個包裝的 Promise,以便在 Promise 變為 fulfilled 后恢復該函數,并且暫停執行異步函數,一旦 promise 變為 fulfilled,恢復異步函數的執行。
  • 每個 await 引擎必須創建兩個額外的 Promise(即使右側已經是一個 Promise)并且它需要至少三個 microtask 隊列 ticks(tick 為系統的相對時間單位,也被稱為系統的時基,來源于定時器的周期性中斷(輸出脈沖),一次中斷表示一個 tick,也被稱做一個“時鐘滴答”、時標。)。

引用賀老師知乎上的一個例子

  1. async function f() { 
  2. await p 
  3. console.log('ok'

簡化理解為:

  1. function f() { 
  2. return RESOLVE(p).then(() => { 
  3. console.log('ok'
  4. }) 
  • 如果 RESOLVE(p) 對于 p 為 promise 直接返回 p 的話,那么 p 的 then 方法就會被馬上調用,其回調就立即進入 job 隊列。
  • 而如果 RESOLVE(p) 嚴格按照標準,應該是產生一個新的 promise,盡管該 promise 確定會 resolve 為 p,但這個過程本身是異步的,也就是現在進入 job 隊列的是新 promise 的 resolve 過程,所以該 promise 的 then 不會被立即調用,而要等到當前 job 隊列執行到前述 resolve 過程才會被調用,然后其回調(也就是繼續 await 之后的語句)才加入 job 隊列,所以時序上就晚了。

谷歌(金絲雀)73 版本中

  • 使用對 PromiseResolve 的調用來更改 await 的語義,以減少在公共 awaitPromise 情況下的轉換次數。
  • 如果傳遞給 await 的值已經是一個 Promise,那么這種優化避免了再次創建 Promise 包裝器,在這種情況下,我們從最少三個 microtick 到只有一個 microtick。

詳細過程:
73 以下版本
首先,打印 script start,調用 async1()時,返回一個 Promise,所以打印出來 async2 end。每個 await,會新產生一個 promise,但這個過程本身是異步的,所以該 await 后面不會立即調用。繼續執行同步代碼,打印 Promise 和 script end,將 then 函數放入微任務隊列中等待執行。同步執行完成之后,檢查微任務隊列是否為 null,然后按照先入先出規則,依次執行。然后先執行打印 promise1,此時 then 的回調函數返回 undefinde,此時又有 then 的鏈式調用,又放入微任務隊列中,再次打印 promise2。再回到 await 的位置執行返回的 Promise 的 resolve 函數,這又會把 resolve 丟到微任務隊列中,打印 async1 end。當微任務隊列為空時,執行宏任務,打印 setTimeout。

谷歌(金絲雀 73 版本)
如果傳遞給 await 的值已經是一個 Promise,那么這種優化避免了再次創建 Promise 包裝器,在這種情況下,我們從最少三個 microtick 到只有一個 microtick。引擎不再需要為 await 創造 throwaway Promise - 在絕大部分時間。現在 promise 指向了同一個 Promise,所以這個步驟什么也不需要做。然后引擎繼續像以前一樣,創建 throwaway Promise,安排 PromiseReactionJob 在 microtask 隊列的下一個 tick 上恢復異步函數,暫停執行該函數,然后返回給調用者。具體詳情查看(這里[5])。

NodeJS 的 Event Loop[6]

Node 中的 Event Loop 是基于 libuv 實現的,而 libuv 是 Node 的新跨平臺抽象層,libuv 使用異步,事件驅動的編程方式,核心是提供 i/o 的事件循環和異步回調。libuv 的 API 包含有時間,非阻塞的網絡,異步文件操作,子進程等等。Event Loop 就是在 libuv 中實現的。

Node[7] 的 Event loop 一共分為 6 個階段,每個細節具體如下:

  • timers: 執行 setTimeout 和 setInterval 中到期的 callback。
  • pending callback: 上一輪循環中少數的 callback 會放在這一階段執行。
  • idle, prepare: 僅在內部使用。
  • poll: 最重要的階段,執行 pending callback,在適當的情況下回阻塞在這個階段。
  • check: 執行 setImmediate(setImmediate()是將事件插入到事件隊列尾部,主線程和事件隊列的函數執行完成之后立即執行 setImmediate 指定的回調函數)的 callback。
  • close callbacks: 執行 close 事件的 callback,例如 socket.on('close'[,fn])或者 http.server.on('close, fn)。具體細節如下:

timers
執行 setTimeout 和 setInterval 中到期的 callback,執行這兩者回調需要設置一個毫秒數,理論上來說,應該是時間一到就立即執行 callback 回調,但是由于 system 的調度可能會延時,達不到預期時間。以下是官網文檔[8]解釋的例子:

  1. const fs = require('fs'); 
  2.  
  3. function someAsyncOperation(callback) { 
  4. // Assume this takes 95ms to complete 
  5. fs.readFile('/path/to/file', callback); 
  6.  
  7. const timeoutScheduled = Date.now(); 
  8.  
  9. setTimeout(() => { 
  10. const delay = Date.now() - timeoutScheduled; 
  11.  
  12. console.log(`${delay}ms have passed since I was scheduled`); 
  13. }, 100); 
  14.  
  15. // do someAsyncOperation which takes 95 ms to complete 
  16. someAsyncOperation(() => { 
  17. const startCallback = Date.now(); 
  18.  
  19. // do something that will take 10ms... 
  20. while (Date.now() - startCallback < 10) { 
  21. // do nothing 
  22. }); 

當進入事件循環時,它有一個空隊列(fs.readFile()尚未完成),因此定時器將等待剩余毫秒數,當到達 95ms 時,fs.readFile()完成讀取文件并且其完成需要 10 毫秒的回調被添加到輪詢隊列并執行。當回調結束時,隊列中不再有回調,因此事件循環將看到已達到最快定時器的閾值,然后回到 timers 階段以執行定時器的回調。

在此示例中,您將看到正在調度的計時器與正在執行的回調之間的總延遲將為 105 毫秒。

以下是我測試時間:

pending callbacks
此階段執行某些系統操作(例如 TCP 錯誤類型)的回調。例如,如果 TCP socket ECONNREFUSED 在嘗試 connect 時 receives,則某些* nix 系統希望等待報告錯誤。這將在 pending callbacks 階段執行。

poll
該 poll 階段有兩個主要功能:

  • 執行 I/O 回調。
  • 處理輪詢隊列中的事件。

當事件循環進入 poll 階段并且在 timers 中沒有可以執行定時器時,將發生以下兩種情況之一

  • 如果 poll 隊列不為空,則事件循環將遍歷其同步執行它們的 callback 隊列,直到隊列為空,或者達到 system-dependent(系統相關限制)。
  • 如果 poll 隊列為空,則會發生以下兩種情況之一
  • 如果有 setImmediate()回調需要執行,則會立即停止執行 poll 階段并進入執行 check 階段以執行回調。
  • 如果沒有 setImmediate()回到需要執行,poll 階段將等待 callback 被添加到隊列中,然后立即執行。

當然設定了 timer 的話且 poll 隊列為空,則會判斷是否有 timer 超時,如果有的話會回到 timer 階段執行回調。
check
此階段允許人員在 poll 階段完成后立即執行回調。如果 poll 階段閑置并且 script 已排隊 setImmediate(),則事件循環到達 check 階段執行而不是繼續等待。

setImmediate()實際上是一個特殊的計時器,它在事件循環的一個單獨階段運行。它使用 libuv API 來調度在 poll 階段完成后執行的回調。

通常,當代碼被執行時,事件循環最終將達到poll階段,它將等待傳入連接,請求等。但是,如果已經調度了回調 setImmediate(),并且輪詢階段變為空閑,則它將結束并且到達check階段,而不是等待 poll 事件。

  1. console.log('start'
  2. setTimeout(() => { 
  3. console.log('timer1'
  4. Promise.resolve().then(function() { 
  5. console.log('promise1'
  6. }) 
  7. }, 0) 
  8. setTimeout(() => { 
  9. console.log('timer2'
  10. Promise.resolve().then(function() { 
  11. console.log('promise2'
  12. }) 
  13. }, 0) 
  14. Promise.resolve().then(function() { 
  15. console.log('promise3'
  16. }) 
  17. console.log('end'

如果 node 版本為 v11.x, 其結果與瀏覽器一致。

  1. start 
  2. end 
  3. promise3 
  4. timer1 
  5. promise1 
  6. timer2 
  7. promise2 

具體詳情可以查看《又被 node 的 eventloop 坑了,這次是 node 的鍋》[9]。

如果 v10 版本上述結果存在兩種情況:

  • 如果 time2 定時器已經在執行隊列中了
  1. start 
  2. end 
  3. promise3 
  4. timer1 
  5. timer2 
  6. promise1 
  7. promise2 
  • 如果 time2 定時器沒有在執行對列中,執行結果為
  1. start 
  2. end 
  3. promise3 
  4. timer1 
  5. promise1 
  6. timer2 
  7. promise2 

具體情況可以參考 poll 階段的兩種情況。

從下圖可能更好理解:

setImmediate() 的 setTimeout()的區別
setImmediate 和 setTimeout()是相似的,但根據它們被調用的時間以不同的方式表現。

  • setImmediate()設計用于在當前 poll 階段完成后check階段執行腳本 。
  • setTimeout() 安排在經過最小(ms)后運行的腳本,在 timers 階段執行。舉個例子
  1. setTimeout(() => { 
  2. console.log('timeout'); 
  3. }, 0); 
  4.  
  5. setImmediate(() => { 
  6. console.log('immediate'); 
  7. }); 

執行定時器的順序將根據調用它們的上下文而有所不同。如果從主模塊中調用兩者,那么時間將受到進程性能的限制。

其結果也不一致

如果在 I / O 周期內移動兩個調用,則始終首先執行立即回調:

  1. const fs = require('fs'); 
  2.  
  3. fs.readFile(\_\_filename, () => { 
  4. setTimeout(() => { 
  5. console.log('timeout'); 
  6. }, 0); 
  7. setImmediate(() => { 
  8. console.log('immediate'); 
  9. }); 
  10. }); 

其結果可以確定一定是 immediate => timeout。主要原因是在 I/O 階段讀取文件后,事件循環會先進入 poll 階段,發現有 setImmediate 需要執行,會立即進入 check 階段執行 setImmediate 的回調。

然后再進入 timers 階段,執行 setTimeout,打印 timeout。

  1. ┌───────────────────────────┐ 
  2. ┌─>│ timers │ 
  3. │ └─────────────┬─────────────┘ 
  4. │ ┌─────────────┴─────────────┐ 
  5. │ │ pending callbacks │ 
  6. │ └─────────────┬─────────────┘ 
  7. │ ┌─────────────┴─────────────┐ 
  8. │ │ idle, prepare │ 
  9. │ └─────────────┬─────────────┘ ┌───────────────┐ 
  10. │ ┌─────────────┴─────────────┐ │ incoming: │ 
  11. │ │ poll │<─────┤ connections, │ 
  12. │ └─────────────┬─────────────┘ │ data, etc. │ 
  13. │ ┌─────────────┴─────────────┐ └───────────────┘ 
  14. │ │ check │ 
  15. │ └─────────────┬─────────────┘ 
  16. │ ┌─────────────┴─────────────┐ 
  17. └──┤ close callbacks │ 
  18. └───────────────────────────┘ 

Process.nextTick()
process.nextTick()雖然它是異步 API 的一部分,但未在圖中顯示。這是因為 process.nextTick()從技術上講,它不是事件循環的一部分。

process.nextTick()方法將 callback 添加到 next tick 隊列。一旦當前事件輪詢隊列的任務全部完成,在 next tick 隊列中的所有 callbacks 會被依次調用。換種理解方式:

當每個階段完成后,如果存在nextTick隊列,就會清空隊列中的所有回調函數,并且優先于其他 microtask 執行。例子

  1. let bar; 
  2.  
  3. setTimeout(() => { 
  4. console.log('setTimeout'); 
  5. }, 0) 
  6.  
  7. setImmediate(() => { 
  8. console.log('setImmediate'); 
  9. }) 
  10. function someAsyncApiCall(callback) { 
  11. process.nextTick(callback); 
  12.  
  13. someAsyncApiCall(() => { 
  14. console.log('bar', bar); // 1 
  15. }); 
  16.  
  17. bar = 1; 

在 NodeV10 中上述代碼執行可能有兩種答案,一種為:

  1. bar 1 
  2. setTimeout 
  3. setImmediate 

另一種為:

  1. bar 1 
  2. setImmediate 
  3. setTimeout 

最后
感謝@Dante_Hu 提出這個問題 await 的問題,文章已經修正。修改了 node 端執行結果。V10 和 V11 的區別。

參考資料

 

[1]

MutationObserver: https://javascript.ruanyifeng.com/dom/mutationobserver.html

[2]

jS事件循環機制: https://segmentfault.com/a/1190000015559210

[3]

事件循環的進程模型: https://segmentfault.com/a/1190000010622146

[4]

Tasks, microtasks, queues and schedules: https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/

[5]

Promise : https://v8.js.cn/blog/fast-async/

[6]

瀏覽器與Node的事件循環(Event Loop)有何區別?: https://juejin.im/post/6844903761949753352

[7]

不要混淆nodejs和瀏覽器中的event loop: https://cnodejs.org/topic/5a9108d78d6e16e56bb80882

[8]

The Node.js Event Loop, Timers, and process.nextTick(): https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/

[9]

《又被 node 的 eventloop 坑了,這次是 node 的鍋》: https://juejin.im/post/6844903761979113479

 

 

 

責任編輯:姜華 來源: 小丑的小屋
相關推薦

2024-05-20 00:00:00

代碼主線程

2025-04-09 10:36:32

2024-10-09 12:05:27

2019-11-08 16:05:54

Promise前端鏈式調用

2019-09-12 09:40:34

秒殺系統高并發

2018-08-07 14:45:52

編程語言JavaScripthtml

2021-12-03 12:15:01

QT中文亂碼Windows

2009-11-27 10:31:02

GPRS路由

2023-02-27 08:08:54

Pulsar源碼重復消費

2025-03-03 00:13:50

2010-01-11 18:05:24

VB.NET窗體繼承

2010-01-04 15:05:53

2023-11-28 08:36:16

Spring中Body讀取

2025-06-17 06:40:45

DockerDocker鏡像

2009-12-25 09:39:08

ADSL MODEM

2025-08-07 02:45:00

2010-01-14 10:19:05

2009-11-24 19:50:10

2009-12-03 18:45:41

2022-10-08 23:55:58

iOS蘋果開發
點贊
收藏

51CTO技術棧公眾號

99久久99久久免费精品蜜臀| 亚洲小说区图片区| 欧美色视频在线观看| 宅男一区二区三区| 亚洲精选一区二区三区| 久久久夜夜夜| 欧美精品在线免费观看| 3d动漫精品啪啪一区二区下载 | 97在线视频免费播放| 国产美女免费网站| 99久热这里只有精品视频免费观看| 色婷婷精品久久二区二区蜜臀av| 免费看啪啪网站| 飘雪影视在线观看免费观看 | 欧美日韩三级| 国产亚洲免费的视频看| 久久免费精品国产| 欧美jizz18| 色视频成人在线观看免| 欧美一级视频在线播放| 欧美13一16娇小xxxx| 97精品久久久午夜一区二区三区| 91久久久久久久久久久| 久久久精品毛片| 亚洲国产精品第一区二区| 日韩有码在线电影| 欧洲av一区二区三区| 成人影院中文字幕| 日韩一区二区视频| 亚洲一区精品视频在线观看| 偷拍精品精品一区二区三区| 亚洲aaa精品| 肉大捧一出免费观看网站在线播放| 国产精品久久久久一区二区国产| 成人av在线一区二区三区| 成人免费看片视频| 亚洲午夜激情视频| 日韩精品国产精品| 欧洲精品在线视频| a v视频在线观看| 亚洲福利一区| 欧美激情奇米色| 黄页网站免费观看| 综合久久亚洲| 欧美精品情趣视频| 玖玖爱这里只有精品| 91成人超碰| 久久精品国产亚洲一区二区| 日本美女黄色一级片| sdde在线播放一区二区| 一道本无吗dⅴd在线播放一区| 国产亚洲无码精品| 真实原创一区二区影院| 亚洲男人天堂九九视频| 3d动漫精品啪啪一区二区下载| 天堂av一区二区三区在线播放| 亚洲精品动漫100p| 免费观看一级一片| 国产欧美一区| 日韩在线观看免费网站| 日韩三级在线观看视频| 午夜欧美精品久久久久久久| 久久久精品在线| 中文字幕在线观看成人| 欧美在线视屏| 久久久久久久久久久免费 | 久cao在线| 亚洲黄色小视频| 国产一二三在线视频| 亚洲v.com| 欧美视频一区二区三区四区| 国产九九在线观看| 久久精品九色| 亚洲精品福利视频| 中文字幕伦理片| 天天影视天天精品| 久久久视频免费观看| 亚洲黄色激情视频| 久久成人麻豆午夜电影| 91久久偷偷做嫩草影院| 亚洲 美腿 欧美 偷拍| 久久久久久97三级| 公共露出暴露狂另类av| 97在线超碰| 欧美在线一二三| 夜夜爽久久精品91| 人妖一区二区三区| 最新中文字幕亚洲| 久久97人妻无码一区二区三区| 亚洲伦伦在线| 91精品久久久久久久久久| 精品人妻少妇AV无码专区| hitomi一区二区三区精品| 亚洲 日韩 国产第一区| ririsao久久精品一区| 91成人网在线| 国产清纯白嫩初高中在线观看性色| 亚洲精品国模| 欧美成人一区在线| 欧美亚洲另类小说| 豆国产96在线|亚洲| 日韩成人在线资源| 黄色美女视频在线观看| 欧美熟乱第一页| 国产伦精品一区二区三区88av| 精品日本12videosex| 色与欲影视天天看综合网| 国产又粗又猛又爽又| 粉嫩13p一区二区三区| 在线观看亚洲视频啊啊啊啊| 天堂电影一区| 日韩欧美综合在线| 国产白丝一区二区三区 | 日本不卡二三区| 性欧美激情精品| 国产精品视频第一页| 久久久精品蜜桃| 国产日韩亚洲欧美在线| 57pao成人永久免费| 亚洲男人天堂视频| 久久99精品波多结衣一区| 国产成人av福利| 热这里只有精品| 成人高清一区| 国产一区二区久久精品| www.av麻豆| 高清国产一区二区三区| 中文字幕在线观看一区二区三区| 日日av拍夜夜添久久免费| 亚洲第一页中文字幕| 欧美精品videos极品| 国产精品996| 久久久成人精品一区二区三区| 91天天综合| 亚洲免费av电影| 国产一级做a爱片久久毛片a| 成人18视频在线播放| 嫩草影院中文字幕| 涩爱av色老久久精品偷偷鲁| 欧美另类69精品久久久久9999| 亚洲专区第一页| 一区免费观看视频| 天堂中文av在线| 久久综合成人| 国产一区二区在线免费| 免费的黄网站在线观看| 91精品国产综合久久小美女| 亚洲二区在线播放| 国产精品一区二区久久不卡| 日本精品福利视频| 大奶在线精品| 91国产精品电影| 欧洲亚洲精品视频| 在线观看成人小视频| 性猛交娇小69hd| 久久成人免费电影| 黄色一级片av| 成人精品毛片| 91成人性视频| 国模吧精品人体gogo| 在线免费观看日韩欧美| 成人午夜免费影院| 国产美女在线精品| 国产成人艳妇aa视频在线| 国产精品nxnn| 日本久久久久久久久久久| 国产女主播在线直播| 欧美日韩亚洲丝袜制服| 玖玖爱这里只有精品| 不卡一区在线观看| 老头吃奶性行交视频| 成人系列视频| eeuss一区二区三区| 嗯啊主人调教在线播放视频| 亚洲人午夜精品| 91精品国产综合久| 亚洲国产三级在线| 日本一级免费视频| 国产精一品亚洲二区在线视频| 性欧美大战久久久久久久| 精品福利久久久| ts人妖另类在线| 国产传媒在线| 日韩中文字幕国产精品| 国产高清视频免费观看| 欧美日韩免费在线| 老司机深夜福利网站| 粉嫩av一区二区三区在线播放| 成人羞羞国产免费网站| 亚洲国产精品成人| 九九九九精品| 成人97精品毛片免费看| 97香蕉超级碰碰久久免费软件| 自拍视频在线网| 亚洲国产高潮在线观看| 在线免费看av片| 天天色综合成人网| 在线观看美女av| 久久综合999| 制服下的诱惑暮生| 久色成人在线| 乱熟女高潮一区二区在线| 免费视频国产一区| 国产精品日韩欧美一区二区三区| 欧美va在线观看| 97视频在线观看免费| av免费在线免费观看| 国产亚洲视频在线观看| 日韩中文字幕影院| 欧美一区午夜精品| 国产天堂第一区| 欧美性xxxx极品高清hd直播 | 欧美理论在线| 亚洲高清视频一区| 久草成人在线| 国产欧美日韩一区| 精品91福利视频| 国产精品一区二区三区在线播放 | yellow视频在线观看一区二区| 日本在线中文字幕一区二区三区| 午夜精品一区二区三区av| 国产丝袜在线| 日韩中文字幕在线精品| 国产二区视频在线观看| 亚洲精品久久久久中文字幕二区| 一区二区三区黄色片| 色www精品视频在线观看| 日本三级中文字幕| 亚洲一区二区三区激情| 在线观看亚洲网站| 中文字幕日韩欧美一区二区三区| 性猛交ⅹxxx富婆video| 91免费小视频| 女人被狂躁c到高潮| 国产69精品久久久久毛片| 少妇性l交大片7724com| 精品一区二区三区av| 天天干天天av| 精品亚洲成a人在线观看| 人人干人人干人人| 蜜乳av一区二区三区| 久久久久久三级| 日本欧美在线看| 国产又黄又猛又粗又爽的视频| 久久久蜜桃一区二区人| 成人3d动漫一区二区三区| 日韩在线观看一区二区| 日本成人中文字幕在线| 三级久久三级久久| 狠狠躁狠狠躁视频专区| 日韩二区三区在线观看| 日本免费观看网站| 奇米精品一区二区三区在线观看一| av在线无限看| 九九精品视频在线看| 亚洲视频在线不卡| 国产.精品.日韩.另类.中文.在线.播放 | 精品无人区一区二区三区| 欧美国产极品| 日本午夜一区二区三区| 日韩理论电影| 九一免费在线观看| 欧美特黄一级| 女性女同性aⅴ免费观女性恋| 美女日韩在线中文字幕| 国产精品区在线| 国产精品资源站在线| 在线精品视频播放| 久久丝袜美腿综合| 国产一区第一页| 亚洲v中文字幕| 成人毛片一区二区三区| 欧美电影影音先锋| 亚洲AV无码一区二区三区性 | 免费a级毛片在线播放| 欧美日韩成人在线视频| 天堂av在线| 成人两性免费视频| 激情小说亚洲色图| 日本在线成人一区二区| 亚洲成人三区| 青青在线视频观看| 国产一区二区在线观看免费| 精品人妻伦一二三区久| 欧美激情一区二区三区全黄| 久久成人在线观看| 日本精品视频一区二区三区| av一级黄色片| 亚洲片av在线| 污污的网站在线看| 国产不卡在线观看| 亚洲精品福利| 日日骚一区二区网站| 狠狠爱综合网| 亚洲另类第一页| 不卡的看片网站| 亚洲一二三四五六区| 欧美日韩国产精品一区二区三区四区 | av在线不卡免费| 91精品久久久久久久久不口人| 日韩欧美在线精品| 国产免费xxx| 日韩黄色免费电影| 丰满大乳奶做爰ⅹxx视频| 亚洲免费看黄网站| 天干夜夜爽爽日日日日| 日韩午夜激情免费电影| 在线免费黄色| 国产成人精品av| 蜜桃一区av| 久久香蕉视频网站| 麻豆久久久久久久| 男人舔女人下部高潮全视频| 婷婷综合久久一区二区三区| 国产草草影院ccyycom| 中文字幕亚洲色图| 一二区成人影院电影网| 国严精品久久久久久亚洲影视 | 色综合视频网站| 国产精品黄色片| 欧美色欧美亚洲另类七区| 亚洲激情偷拍| 在线观看一区二区三区四区| 亚洲欧美在线aaa| 色婷婷久久综合中文久久蜜桃av| 日韩精品视频中文在线观看| 另类视频在线| av观看久久| 一区二区亚洲精品| 秋霞午夜鲁丝一区二区| 亚洲三级免费观看| 国产一区二区在线视频观看| 这里精品视频免费| 成人在线观看免费播放| 日韩一区二区三区资源| 玖玖视频精品| 国产aⅴ激情无码久久久无码| 欧美视频专区一二在线观看| 四虎电影院在线观看| 浅井舞香一区二区| 九九综合九九| 一级黄色香蕉视频| 欧美国产丝袜视频| 最新中文字幕第一页| 爽爽爽爽爽爽爽成人免费观看| 国产成人精品亚洲日本在线观看| 日本精品二区| 免费观看成人av| 少妇高潮一区二区三区喷水| 欧美日韩1234| 国产在线一区二区视频| 99在线国产| 亚洲全部视频| 麻豆av免费观看| 欧美性一级生活| а√天堂资源地址在线下载| 99国产在线观看| 99热在线精品观看| 91中文字幕永久在线| 欧美色大人视频| 国产福利视频在线| 成人av在线网址| 91久久亚洲| 欧美黄色一级生活片| 欧美日韩成人综合在线一区二区| 超鹏97在线| 精品乱码一区二区三区| 久久婷婷av| 三级全黄做爰视频| 亚洲第一区中文字幕| 丝袜美腿一区| 中日韩在线视频| av中文字幕一区| 成年人视频免费| 欧美另类极品videosbestfree| 牛牛精品成人免费视频| 狠狠躁狠狠躁视频专区| 夜夜夜精品看看| 国产有码在线| 91国产在线免费观看| 国产精品美女久久久浪潮软件| 一级黄色录像毛片| 精品日韩一区二区| 亚洲天堂一区二区| dy888午夜| 久久久久一区二区三区四区| 一级特黄aaa大片| 久久露脸国产精品| 日韩精品一卡| 日本一区二区在线免费观看| 欧美日韩在线精品一区二区三区激情 | 国产理论视频在线观看| 4438全国亚洲精品在线观看视频| 日韩综合网站| 黄色在线观看av| 日韩欧美在线观看一区二区三区| 欧美一级大片| 亚洲理论电影在线观看| 国产精品女同互慰在线看| 四虎精品一区二区三区|