久久福利_99r_国产日韩在线视频_直接看av的网站_中文欧美日韩_久久一

您的位置:首頁技術(shù)文章
文章詳情頁

從瀏覽器多進程到JS單線程,JS運行機制最全面的一次梳理

瀏覽:134日期:2024-05-26 14:29:58
前言

見解有限,如有描述不當(dāng)之處,請幫忙及時指出,如有錯誤,會及時修正。

———-超長文+多圖預(yù)警,需要花費不少時間。———-

如果看完本文后,還對進程線程傻傻分不清,不清楚瀏覽器多進程、瀏覽器內(nèi)核多線程、JS單線程、JS運行機制的區(qū)別。那么請回復(fù)我,一定是我寫的還不夠清晰,我來改。。。

———-正文開始———-

最近發(fā)現(xiàn)有不少介紹JS單線程運行機制的文章,但是發(fā)現(xiàn)很多都僅僅是介紹某一部分的知識,而且各個地方的說法還不統(tǒng)一,容易造成困惑。 因此準(zhǔn)備梳理這塊知識點,結(jié)合已有的認知,基于網(wǎng)上的大量參考資料, 從瀏覽器多進程到JS單線程,將JS引擎的運行機制系統(tǒng)的梳理一遍。

展現(xiàn)形式:由于是屬于系統(tǒng)梳理型,就沒有由淺入深了,而是從頭到尾的梳理知識體系, 重點是將關(guān)鍵節(jié)點的知識點串聯(lián)起來,而不是僅僅剖析某一部分知識。

內(nèi)容是:從瀏覽器進程,再到瀏覽器內(nèi)核運行,再到JS引擎單線程,再到JS事件循環(huán)機制,從頭到尾系統(tǒng)的梳理一遍,擺脫碎片化,形成一個知識體系

目標(biāo)是:看完這篇文章后,對瀏覽器多進程,JS單線程,JS事件循環(huán)機制這些都能有一定理解, 有一個知識體系骨架,而不是似懂非懂的感覺。

另外,本文適合有一定經(jīng)驗的前端人員, 新手請規(guī)避 ,避免受到過多的概念沖擊。可以先存起來,有了一定理解后再看,也可以分成多批次觀看,避免過度疲勞。

大綱

區(qū)分進程和線程

瀏覽器是多進程的

瀏覽器都包含哪些進程?

瀏覽器多進程的優(yōu)勢

重點是瀏覽器內(nèi)核(渲染進程)

Browser進程和瀏覽器內(nèi)核(Renderer進程)的通信過程

梳理瀏覽器內(nèi)核中線程之間的關(guān)系

GUI渲染線程與JS引擎線程互斥

JS阻塞頁面加載

WebWorker,JS的多線程?

WebWorker與SharedWorker

簡單梳理下瀏覽器渲染流程

load事件與DOMContentLoaded事件的先后

css加載是否會阻塞dom樹渲染?

普通圖層和復(fù)合圖層

從Event Loop談JS的運行機制

事件循環(huán)機制進一步補充

單獨說說定時器

setTimeout而不是setInterval

事件循環(huán)進階:macrotask與microtask

寫在最后的話

區(qū)分進程和線程

線程和進程區(qū)分不清,是很多新手都會犯的錯誤,沒有關(guān)系。這很正常。先看看下面這個形象的比喻:

- 進程是一個工廠,工廠有它的獨立資源- 工廠之間相互獨立- 線程是工廠中的工人,多個工人協(xié)作完成任務(wù)- 工廠內(nèi)有一個或多個工人- 工人之間共享空間

再完善完善概念:

- 工廠的資源 -> 系統(tǒng)分配的內(nèi)存(獨立的一塊內(nèi)存)- 工廠之間的相互獨立 -> 進程之間相互獨立- 多個工人協(xié)作完成任務(wù) -> 多個線程在進程中協(xié)作完成任務(wù)- 工廠內(nèi)有一個或多個工人 -> 一個進程由一個或多個線程組成- 工人之間共享空間 -> 同一進程下的各個線程之間共享程序的內(nèi)存空間(包括代碼段、數(shù)據(jù)集、堆等)

然后再鞏固下:

如果是windows電腦中,可以打開任務(wù)管理器,可以看到有一個后臺進程列表。對,那里就是查看進程的地方,而且可以看到每個進程的內(nèi)存資源信息以及cpu占有率。

從瀏覽器多進程到JS單線程,JS運行機制最全面的一次梳理

所以,應(yīng)該更容易理解了: 進程是cpu資源分配的最小單位(系統(tǒng)會給它分配內(nèi)存)

最后,再用較為官方的術(shù)語描述一遍:

進程是cpu資源分配的最小單位(是能擁有資源和獨立運行的最小單位)

線程是cpu調(diào)度的最小單位(線程是建立在進程的基礎(chǔ)上的一次程序運行單位,一個進程中可以有多個線程)

tips

不同進程之間也可以通信,不過代價較大

現(xiàn)在,一般通用的叫法: 單線程與多線程 ,都是指 在一個進程內(nèi) 的單和多。(所以核心還是得屬于一個進程才行)

瀏覽器是多進程的

理解了進程與線程了區(qū)別后,接下來對瀏覽器進行一定程度上的認識:(先看下簡化理解)

瀏覽器是多進程的

瀏覽器之所以能夠運行,是因為系統(tǒng)給它的進程分配了資源(cpu、內(nèi)存)

簡單點理解,每打開一個Tab頁,就相當(dāng)于創(chuàng)建了一個獨立的瀏覽器進程。

關(guān)于以上幾點的驗證, 請再第一張圖

從瀏覽器多進程到JS單線程,JS運行機制最全面的一次梳理

圖中打開了 Chrome 瀏覽器的多個標(biāo)簽頁,然后可以在 Chrome的任務(wù)管理器 中看到有多個進程(分別是每一個Tab頁面有一個獨立的進程,以及一個主進程)。 感興趣的可以自行嘗試下,如果再多打開一個Tab頁,進程正常會+1以上

注意:在這里瀏覽器應(yīng)該也有自己的優(yōu)化機制,有時候打開多個tab頁后,可以在Chrome任務(wù)管理器中看到,有些進程被合并了 (所以每一個Tab標(biāo)簽對應(yīng)一個進程并不一定是絕對的)

瀏覽器都包含哪些進程?

知道了瀏覽器是多進程后,再來看看它到底包含哪些進程:(為了簡化理解,僅列舉主要進程)

Browser進程:瀏覽器的主進程(負責(zé)協(xié)調(diào)、主控),只有一個。作用有

負責(zé)瀏覽器界面顯示,與用戶交互。如前進,后退等

負責(zé)各個頁面的管理,創(chuàng)建和銷毀其他進程

將Renderer進程得到的內(nèi)存中的Bitmap,繪制到用戶界面上

網(wǎng)絡(luò)資源的管理,下載等

第三方插件進程:每種類型的插件對應(yīng)一個進程,僅當(dāng)使用該插件時才創(chuàng)建

GPU進程:最多一個,用于3D繪制等

瀏覽器渲染進程(瀏覽器內(nèi)核)(Renderer進程,內(nèi)部是多線程的):默認每個Tab頁面一個進程,互不影響。主要作用為

頁面渲染,腳本執(zhí)行,事件處理等

強化記憶: 在瀏覽器中打開一個網(wǎng)頁相當(dāng)于新起了一個進程(進程內(nèi)有自己的多線程)

當(dāng)然,瀏覽器有時會將多個進程合并(譬如打開多個空白標(biāo)簽頁后,會發(fā)現(xiàn)多個空白標(biāo)簽頁被合并成了一個進程),如圖

從瀏覽器多進程到JS單線程,JS運行機制最全面的一次梳理

另外,可以通過Chrome的 更多工具 -> 任務(wù)管理器 自行驗證

瀏覽器多進程的優(yōu)勢

相比于單進程瀏覽器,多進程有如下優(yōu)點:

避免單個page crash影響整個瀏覽器

避免第三方插件crash影響整個瀏覽器

多進程充分利用多核優(yōu)勢

方便使用沙盒模型隔離插件等進程,提高瀏覽器穩(wěn)定性

簡單點理解: 如果瀏覽器是單進程,那么某個Tab頁崩潰了,就影響了整個瀏覽器,體驗有多差;同理如果是單進程,插件崩潰了也會影響整個瀏覽器;而且多進程還有其它的諸多優(yōu)勢。。。

當(dāng)然,內(nèi)存等資源消耗也會更大,有點空間換時間的意思。

重點是瀏覽器內(nèi)核(渲染進程)

重點來了,我們可以看到,上面提到了這么多的進程,那么,對于普通的前端操作來說,最終要的是什么呢?答案是 渲染進程

可以這樣理解,頁面的渲染,JS的執(zhí)行,事件的循環(huán),都在這個進程內(nèi)進行。接下來重點分析這個進程

請牢記,瀏覽器的渲染進程是多線程的(這點如果不理解, 請回頭看進程和線程的區(qū)分

終于到了線程這個概念了:sob:,好親切。那么接下來看看它都包含了哪些線程(列舉一些主要常駐線程):

GUI渲染線程

負責(zé)渲染瀏覽器界面,解析HTML,CSS,構(gòu)建DOM樹和RenderObject樹,布局和繪制等。

當(dāng)界面需要重繪(Repaint)或由于某種操作引發(fā)回流(reflow)時,該線程就會執(zhí)行

注意, GUI渲染線程與JS引擎線程是互斥的 ,當(dāng)JS引擎執(zhí)行時GUI線程會被掛起(相當(dāng)于被凍結(jié)了),GUI更新會被保存在一個隊列中 等到JS引擎空閑時 立即被執(zhí)行。

JS引擎線程

也稱為JS內(nèi)核,負責(zé)處理Javascript腳本程序。(例如V8引擎)

JS引擎線程負責(zé)解析Javascript腳本,運行代碼。

JS引擎一直等待著任務(wù)隊列中任務(wù)的到來,然后加以處理,瀏覽器無論什么時候都只有一個JS線程在運行JS程序

同樣注意, GUI渲染線程與JS引擎線程是互斥的 ,所以如果JS執(zhí)行的時間過長,這樣就會造成頁面的渲染不連貫,導(dǎo)致頁面渲染加載阻塞。

事件觸發(fā)線程

歸屬于瀏覽器而不是JS引擎,用來控制事件循環(huán)(可以理解,JS引擎自己都忙不過來,需要瀏覽器另開線程協(xié)助)

當(dāng)JS引擎執(zhí)行代碼塊如setTimeOut時(也可來自瀏覽器內(nèi)核的其他線程,如鼠標(biāo)點擊、AJAX異步請求等),會將對應(yīng)任務(wù)添加到事件線程中

當(dāng)對應(yīng)的事件符合觸發(fā)條件被觸發(fā)時,該線程會把事件添加到待處理隊列的隊尾,等待JS引擎的處理

注意,由于JS的單線程關(guān)系,所以這些待處理隊列中的事件都得排隊等待JS引擎處理(當(dāng)JS引擎空閑時才會去執(zhí)行)

定時觸發(fā)器線程

傳說中的 setInternal 與 setTimeout 所在線程

瀏覽器定時計數(shù)器并不是由JavaScript引擎計數(shù)的,(因為JavaScript引擎是單線程的, 如果處于阻塞線程狀態(tài)就會影響記計時的準(zhǔn)確)

因此通過單獨線程來計時并觸發(fā)定時(計時完畢后,添加到事件隊列中,等待JS引擎空閑后執(zhí)行)

注意,W3C在HTML標(biāo)準(zhǔn)中規(guī)定,規(guī)定要求setTimeout中低于4ms的時間間隔算為4ms。

異步http請求線程

在XMLHttpRequest在連接后是通過瀏覽器新開一個線程請求

將檢測到狀態(tài)變更時,如果設(shè)置有回調(diào)函數(shù),異步線程就 產(chǎn)生狀態(tài)變更事件 ,將這個回調(diào)再放入事件隊列中。再由JavaScript引擎執(zhí)行。

看到這里,如果覺得累了,可以先休息下,這些概念需要被消化,畢竟后續(xù)將提到的事件循環(huán)機制就是基于 事件觸發(fā)線程 的,所以如果僅僅是看某個碎片化知識, 可能會有一種似懂非懂的感覺。要完成的梳理一遍才能快速沉淀,不易遺忘。放張圖鞏固下吧:

從瀏覽器多進程到JS單線程,JS運行機制最全面的一次梳理

再說一點,為什么JS引擎是單線程的?額,這個問題其實應(yīng)該沒有標(biāo)準(zhǔn)答案,譬如,可能僅僅是因為由于多線程的復(fù)雜性,譬如多線程操作一般要加鎖,因此最初設(shè)計時選擇了單線程。。。

Browser進程和瀏覽器內(nèi)核(Renderer進程)的通信過程

看到這里,首先,應(yīng)該對瀏覽器內(nèi)的進程和線程都有一定理解了,那么接下來,再談?wù)劄g覽器的Browser進程(控制進程)是如何和內(nèi)核通信的, 這點也理解后,就可以將這部分的知識串聯(lián)起來,從頭到尾有一個完整的概念。

如果自己打開任務(wù)管理器,然后打開一個瀏覽器,就可以看到: 任務(wù)管理器中出現(xiàn)了兩個進程(一個是主控進程,一個則是打開Tab頁的渲染進程) , 然后在這前提下,看下整個的過程:(簡化了很多)

Browser進程收到用戶請求,首先需要獲取頁面內(nèi)容(譬如通過網(wǎng)絡(luò)下載資源),隨后將該任務(wù)通過RendererHost接口傳遞給Render進程

Renderer進程的Renderer接口收到消息,簡單解釋后,交給渲染線程,然后開始渲染

渲染線程接收請求,加載網(wǎng)頁并渲染網(wǎng)頁,這其中可能需要Browser進程獲取資源和需要GPU進程來幫助渲染

當(dāng)然可能會有JS線程操作DOM(這樣可能會造成回流并重繪)

最后Render進程將結(jié)果傳遞給Browser進程

Browser進程接收到結(jié)果并將結(jié)果繪制出來

這里繪一張簡單的圖:(很簡化)

從瀏覽器多進程到JS單線程,JS運行機制最全面的一次梳理

看完這一整套流程,應(yīng)該對瀏覽器的運作有了一定理解了,這樣有了知識架構(gòu)的基礎(chǔ)后,后續(xù)就方便往上填充內(nèi)容。

這塊再往深處講的話就涉及到瀏覽器內(nèi)核源碼解析了,不屬于本文范圍。

如果這一塊要深挖,建議去讀一些瀏覽器內(nèi)核源碼解析文章,或者可以先看看參考下來源中的第一篇文章,寫的不錯

梳理瀏覽器內(nèi)核中線程之間的關(guān)系

到了這里,已經(jīng)對瀏覽器的運行有了一個整體的概念,接下來,先簡單梳理一些概念

GUI渲染線程與JS引擎線程互斥

由于JavaScript是可操縱DOM的,如果在修改這些元素屬性同時渲染界面(即JS線程和UI線程同時運行),那么渲染線程前后獲得的元素數(shù)據(jù)就可能不一致了。

因此為了防止渲染出現(xiàn)不可預(yù)期的結(jié)果,瀏覽器設(shè)置GUI渲染線程與JS引擎為互斥的關(guān)系,當(dāng)JS引擎執(zhí)行時GUI線程會被掛起, GUI更新則會被保存在一個隊列中等到JS引擎線程空閑時立即被執(zhí)行。

JS阻塞頁面加載

從上述的互斥關(guān)系,可以推導(dǎo)出,JS如果執(zhí)行時間過長就會阻塞頁面。

譬如,假設(shè)JS引擎正在進行巨量的計算,此時就算GUI有更新,也會被保存到隊列中,等待JS引擎空閑后執(zhí)行。 然后,由于巨量計算,所以JS引擎很可能很久很久后才能空閑,自然會感覺到巨卡無比。

所以,要盡量避免JS執(zhí)行時間過長,這樣就會造成頁面的渲染不連貫,導(dǎo)致頁面渲染加載阻塞的感覺。

WebWorker,JS的多線程?

前文中有提到JS引擎是單線程的,而且JS執(zhí)行時間過長會阻塞頁面,那么JS就真的對cpu密集型計算無能為力么?

所以,后來HTML5中支持了 Web Worker 。

MDN的官方解釋是:

Web Worker為Web內(nèi)容在后臺線程中運行腳本提供了一種簡單的方法。線程可以執(zhí)行任務(wù)而不干擾用戶界面一個worker是使用一個構(gòu)造函數(shù)創(chuàng)建的一個對象(e.g. Worker()) 運行一個命名的JavaScript文件 這個文件包含將在工作線程中運行的代碼; workers 運行在另一個全局上下文中,不同于當(dāng)前的window因此,使用 window快捷方式獲取當(dāng)前全局的范圍 (而不是self) 在一個 Worker 內(nèi)將返回錯誤

這樣理解下:

創(chuàng)建Worker時,JS引擎向瀏覽器申請開一個子線程(子線程是瀏覽器開的,完全受主線程控制,而且不能操作DOM)

JS引擎線程與worker線程間通過特定的方式通信(postMessage API,需要通過序列化對象來與線程交互特定的數(shù)據(jù))

所以,如果有非常耗時的工作,請單獨開一個Worker線程,這樣里面不管如何翻天覆地都不會影響JS引擎主線程, 只待計算出結(jié)果后,將結(jié)果通信給主線程即可,perfect!

而且注意下, JS引擎是單線程的 ,這一點的本質(zhì)仍然未改變,Worker可以理解是瀏覽器給JS引擎開的外掛,專門用來解決那些大量計算問題。

其它,關(guān)于Worker的詳解就不是本文的范疇了,因此不再贅述。

WebWorker與SharedWorker

既然都到了這里,就再提一下 SharedWorker (避免后續(xù)將這兩個概念搞混)

WebWorker只屬于某個頁面,不會和其他頁面的Render進程(瀏覽器內(nèi)核進程)共享

所以Chrome在Render進程中(每一個Tab頁就是一個render進程)創(chuàng)建一個新的線程來運行Worker中的JavaScript程序。

SharedWorker是瀏覽器所有頁面共享的,不能采用與Worker同樣的方式實現(xiàn),因為它不隸屬于某個Render進程,可以為多個Render進程共享使用

所以Chrome瀏覽器為SharedWorker單獨創(chuàng)建一個進程來運行JavaScript程序,在瀏覽器中每個相同的JavaScript只存在一個SharedWorker進程,不管它被創(chuàng)建多少次。

看到這里,應(yīng)該就很容易明白了,本質(zhì)上就是進程和線程的區(qū)別。SharedWorker由獨立的進程管理,WebWorker只是屬于render進程下的一個線程

簡單梳理下瀏覽器渲染流程

本來是直接計劃開始談JS運行機制的,但想了想,既然上述都一直在談瀏覽器,直接跳到JS可能再突兀,因此,中間再補充下瀏覽器的渲染流程(簡單版本)

為了簡化理解,前期工作直接省略成:(要展開的或完全可以寫另一篇超長文)

- 瀏覽器輸入url,瀏覽器主進程接管,開一個下載線程,然后進行 http請求(略去DNS查詢,IP尋址等等操作),然后等待響應(yīng),獲取內(nèi)容,隨后將內(nèi)容通過RendererHost接口轉(zhuǎn)交給Renderer進程- 瀏覽器渲染流程開始

瀏覽器器內(nèi)核拿到內(nèi)容后,渲染大概可以劃分成以下幾個步驟:

解析html建立dom樹

解析css構(gòu)建render樹(將CSS代碼解析成樹形的數(shù)據(jù)結(jié)構(gòu),然后結(jié)合DOM合并成render樹)

布局render樹(Layout/reflow),負責(zé)各元素尺寸、位置的計算

繪制render樹(paint),繪制頁面像素信息

瀏覽器會將各層的信息發(fā)送給GPU,GPU會將各層合成(composite),顯示在屏幕上。

所有詳細步驟都已經(jīng)略去,渲染完畢后就是 load 事件了,之后就是自己的JS邏輯處理了

既然略去了一些詳細的步驟,那么就提一些可能需要注意的細節(jié)把。

load事件與DOMContentLoaded事件的先后

上面提到,渲染完畢后會觸發(fā) load 事件,那么你能分清楚 load 事件與 DOMContentLoaded 事件的先后么?

很簡單,知道它們的定義就可以了:

當(dāng) DOMContentLoaded 事件觸發(fā)時,僅當(dāng)DOM加載完成,不包括樣式表,圖片。 (譬如如果有async加載的腳本就不一定完成)

當(dāng) onload 事件觸發(fā)時,頁面上所有的DOM,樣式表,腳本,圖片都已經(jīng)加載完成了。 (渲染完畢了)

所以,順序是: DOMContentLoaded -> load

css加載是否會阻塞dom樹渲染?

這里說的是頭部引入css的情況

首先,我們都知道: css是由單獨的下載線程異步下載的。

然后再說下幾個現(xiàn)象:

css加載不會阻塞DOM樹解析(異步加載時DOM照常構(gòu)建)

但會阻塞render樹渲染(渲染時需等css加載完畢,因為render樹需要css信息)

這可能也是瀏覽器的一種優(yōu)化機制。

因為你加載css的時候,可能會修改下面DOM節(jié)點的樣式, 如果css加載不阻塞render樹渲染的話,那么當(dāng)css加載完之后, render樹可能又得重新重繪或者回流了,這就造成了一些沒有必要的損耗。 所以干脆就先把DOM樹的結(jié)構(gòu)先解析完,把可以做的工作做完,然后等你css加載完之后, 在根據(jù)最終的樣式來渲染render樹,這種做法性能方面確實會比較好一點。

普通圖層和復(fù)合圖層

渲染步驟中就提到了 composite 概念。

可以簡單的這樣理解,瀏覽器渲染的圖層一般包含兩大類: 普通圖層 以及 復(fù)合圖層

首先,普通文檔流內(nèi)可以理解為一個復(fù)合圖層(這里稱為 默認復(fù)合層 ,里面不管添加多少元素,其實都是在同一個復(fù)合圖層中)

其次,absolute布局(fixed也一樣),雖然可以脫離普通文檔流,但它仍然屬于 默認復(fù)合層 。

然后,可以通過 硬件加速 的方式,聲明一個 新的復(fù)合圖層 ,它會單獨分配資源 (當(dāng)然也會脫離普通文檔流,這樣一來,不管這個復(fù)合圖層中怎么變化,也不會影響 默認復(fù)合層 里的回流重繪)

可以簡單理解下: GPU中,各個復(fù)合圖層是單獨繪制的,所以互不影響 ,這也是為什么某些場景硬件加速效果一級棒

可以 Chrome源碼調(diào)試 -> More Tools -> Rendering -> Layer borders 中看到,黃色的就是復(fù)合圖層信息

如下圖。可以驗證上述的說法

從瀏覽器多進程到JS單線程,JS運行機制最全面的一次梳理

如何變成復(fù)合圖層(硬件加速)

將該元素變成一個復(fù)合圖層,就是傳說中的硬件加速技術(shù)

最常用的方式: translate3d 、 translateZ

opacity 屬性/過渡動畫(需要動畫執(zhí)行的過程中才會創(chuàng)建合成層,動畫沒有開始或結(jié)束后元素還會回到之前的狀態(tài))

will-chang 屬性(這個比較偏僻),一般配合opacity與translate使用(而且經(jīng)測試,除了上述可以引發(fā)硬件加速的屬性外,其它屬性并不會變成復(fù)合層), 作用是提前告訴瀏覽器要變化,這樣瀏覽器會開始做一些優(yōu)化工作(這個最好用完后就釋放)

<video><iframe><canvas><webgl> 等元素

其它,譬如以前的flash插件

absolute和硬件加速的區(qū)別

可以看到,absolute雖然可以脫離普通文檔流,但是無法脫離默認復(fù)合層。 所以,就算absolute中信息改變時不會改變普通文檔流中render樹, 但是,瀏覽器最終繪制時,是整個復(fù)合層繪制的,所以absolute中信息的改變,仍然會影響整個復(fù)合層的繪制。 (瀏覽器會重繪它,如果復(fù)合層中內(nèi)容多,absolute帶來的繪制信息變化過大,資源消耗是非常嚴(yán)重的)

而硬件加速直接就是在另一個復(fù)合層了(另起爐灶),所以它的信息改變不會影響默認復(fù)合層 (當(dāng)然了,內(nèi)部肯定會影響屬于自己的復(fù)合層),僅僅是引發(fā)最后的合成(輸出視圖)

復(fù)合圖層的作用?

一般一個元素開啟硬件加速后會變成復(fù)合圖層,可以獨立于普通文檔流中,改動后可以避免整個頁面重繪,提升性能

但是盡量不要大量使用復(fù)合圖層,否則由于資源消耗過度,頁面反而會變的更卡

硬件加速時請使用index

使用硬件加速時,盡可能的使用index,防止瀏覽器默認給后續(xù)的元素創(chuàng)建復(fù)合層渲染

具體的原理時這樣的: webkit CSS3中,如果這個元素添加了硬件加速,并且index層級比較低, 那么在這個元素的后面其它元素(層級比這個元素高的,或者相同的,并且releative或absolute屬性相同的), 會默認變?yōu)閺?fù)合層渲染,如果處理不當(dāng)會極大的影響性能

簡單點理解,其實可以認為是一個隱式合成的概念: 如果a是一個復(fù)合圖層,而且b在a上面,那么b也會被隱式轉(zhuǎn)為一個復(fù)合圖層 ,這點需要特別注意

另外,這個問題可以在這個地址看到重現(xiàn)(原作者分析的挺到位的,直接上鏈接):

http://web.jobbole.com/83575/

從Event Loop談JS的運行機制

到此時,已經(jīng)是屬于瀏覽器頁面初次渲染完畢后的事情,JS引擎的一些運行機制分析。

注意,這里不談 可執(zhí)行上下文 , VO , scop chain 等概念(這些完全可以整理成另一篇文章了),這里主要是結(jié)合 Event Loop 來談JS代碼是如何執(zhí)行的。

讀這部分的前提是已經(jīng)知道了JS引擎是單線程,而且這里會用到上文中的幾個概念:(如果不是很理解,可以回頭溫習(xí))

JS引擎線程

事件觸發(fā)線程

定時觸發(fā)器線程

然后再理解一個概念:

JS分為同步任務(wù)和異步任務(wù)

同步任務(wù)都在主線程上執(zhí)行,形成一個 執(zhí)行棧

主線程之外, 事件觸發(fā)線程 管理著一個 任務(wù)隊列 ,只要異步任務(wù)有了運行結(jié)果,就在 任務(wù)隊列 之中放置一個事件。

一旦 執(zhí)行棧 中的所有同步任務(wù)執(zhí)行完畢(此時JS引擎空閑),系統(tǒng)就會讀取 任務(wù)隊列 ,將可運行的異步任務(wù)添加到可執(zhí)行棧中,開始執(zhí)行。

看圖:

從瀏覽器多進程到JS單線程,JS運行機制最全面的一次梳理

看到這里,應(yīng)該就可以理解了:為什么有時候setTimeout推入的事件不能準(zhǔn)時執(zhí)行?因為可能在它推入到事件列表時,主線程還不空閑,正在執(zhí)行其它代碼, 所以自然有誤差。

事件循環(huán)機制進一步補充

這里就直接引用一張圖片來協(xié)助理解:(參考自Philip Roberts的演講《 Help, I’m stuck in an event-loop 》)

從瀏覽器多進程到JS單線程,JS運行機制最全面的一次梳理

上圖大致描述就是:

主線程運行時會產(chǎn)生執(zhí)行棧, 棧中的代碼調(diào)用某些api時,它們會在事件隊列中添加各種事件(當(dāng)滿足觸發(fā)條件后,如ajax請求完畢)

而棧中的代碼執(zhí)行完畢,就會讀取事件隊列中的事件,去執(zhí)行那些回調(diào)

如此循環(huán)

注意,總是要等待棧中的代碼執(zhí)行完畢后才會去讀取事件隊列中的事件

單獨說說定時器

上述事件循環(huán)機制的核心是:JS引擎線程和事件觸發(fā)線程

但事件上,里面還有一些隱藏細節(jié),譬如調(diào)用 setTimeout 后,是如何等待特定時間后才添加到事件隊列中的?

是JS引擎檢測的么?當(dāng)然不是了。它是由 定時器線程 控制(因為JS引擎自己都忙不過來,根本無暇分身)

為什么要單獨的定時器線程?因為JavaScript引擎是單線程的, 如果處于阻塞線程狀態(tài)就會影響記計時的準(zhǔn)確,因此很有必要單獨開一個線程用來計時。

什么時候會用到定時器線程? 當(dāng)使用 setTimeout 或 setInterval 時 ,它需要定時器線程計時,計時完成后就會將特定的事件推入事件隊列中。

譬如:

setTimeout(function(){ console.log(’hello!’);}, 1000);

這段代碼的作用是當(dāng) 1000 毫秒計時完畢后(由定時器線程計時),將回調(diào)函數(shù)推入事件隊列中,等待主線程執(zhí)行

setTimeout(function(){ console.log(’hello!’);}, 0);console.log(’begin’);

這段代碼的效果是最快的時間內(nèi)將回調(diào)函數(shù)推入事件隊列中,等待主線程執(zhí)行

注意:

執(zhí)行結(jié)果是:先 begin 后 hello!

雖然代碼的本意是0毫秒后就推入事件隊列,但是W3C在HTML標(biāo)準(zhǔn)中規(guī)定,規(guī)定要求setTimeout中低于4ms的時間間隔算為4ms。 (不過也有一說是不同瀏覽器有不同的最小時間設(shè)定)

就算不等待4秒,就算假設(shè)0毫秒就推入事件隊列,也會先執(zhí)行 begin (因為只有可執(zhí)行棧內(nèi)空了后才會主動讀取事件隊列)

setTimeout而不是setInterval

用setTimeout模擬定期計時和直接用setInterval是有區(qū)別的。

因為每次setTimeout計時到后就會去執(zhí)行,然后執(zhí)行一段時間后才會繼續(xù)setTimeout,中間就多了誤差 (誤差多少與代碼執(zhí)行時間有關(guān))

而setInterval則是每次都精確的隔一段時間推入一個事件 (但是,事件的實際執(zhí)行時間不一定就準(zhǔn)確,還有可能是這個事件還沒執(zhí)行完畢,下一個事件就來了)

而且setInterval有一些比較致命的問題就是:

累計效應(yīng)(上面提到的),如果setInterval代碼在(setInterval)再次添加到隊列之前還沒有完成執(zhí)行, 就會導(dǎo)致定時器代碼連續(xù)運行好幾次,而之間沒有間隔。 就算正常間隔執(zhí)行,多個setInterval的代碼執(zhí)行時間可能會比預(yù)期小(因為代碼執(zhí)行需要一定時間)

譬如像iOS的webview,或者Safari等瀏覽器中都有一個特點, 在滾動的時候是不執(zhí)行JS的 , 如果使用了setInterval,會發(fā)現(xiàn)在滾動結(jié)束后會執(zhí)行多次由于滾動不執(zhí)行JS積攢回調(diào), 如果回調(diào)執(zhí)行時間過長,就會非常容器造成卡頓問題和一些不可知的錯誤

而且把瀏覽器最小化顯示等操作時,setInterval并不是不執(zhí)行程序, 它會把setInterval的回調(diào)函數(shù)放在隊列中,等瀏覽器窗口再次打開時,一瞬間全部執(zhí)行時

所以,鑒于這么多但問題,目前一般認為的最佳方案是: 用setTimeout模擬setInterval,或者特殊場合直接用requestAnimationFrame

事件循環(huán)進階:macrotask與microtask

這段參考了參考來源中的第2篇文章(英文版的),(加了下自己的理解重新描述了下), 強烈推薦有英文基礎(chǔ)的同學(xué)直接觀看原文,作者描述的很清晰,示例也很不錯,如下:

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

上文中將JS事件循環(huán)機制梳理了一遍,在ES5的情況是夠用了,但是在ES6盛行的現(xiàn)在,仍然會遇到一些問題,譬如下面這題:

console.log(’script start’);setTimeout(function() { console.log(’setTimeout’);}, 0);Promise.resolve().then(function() { console.log(’promise1’);}).then(function() { console.log(’promise2’);});console.log(’script end’);

嗯哼,它的正確執(zhí)行順序是這樣子的:

script startscript endpromise1promise2setTimeout

為什么呢?因為Promise里有了一個一個新的概念: microtask

或者,進一步,JS中分為兩種任務(wù)類型: macrotask 和 microtask ,在ECMAScript中,microtask稱為 jobs ,macrotask可稱為 task

它們的定義?區(qū)別?簡單點可以按如下理解:

macrotask(又稱之為宏任務(wù)),可以理解是每次執(zhí)行棧執(zhí)行的代碼就是一個宏任務(wù)(包括每次從事件隊列中獲取一個事件回調(diào)并放到執(zhí)行棧中執(zhí)行)

每一個task會從頭到尾將這個任務(wù)執(zhí)行完畢,不會執(zhí)行其它

瀏覽器為了能夠使得JS內(nèi)部task與DOM任務(wù)能夠有序的執(zhí)行,會在一個task執(zhí)行結(jié)束后,在下一個 task 執(zhí)行開始前,對頁面進行重新渲染 ( task->渲染->task->... )

microtask(又稱為微任務(wù)),可以理解是在當(dāng)前 task 執(zhí)行結(jié)束后立即執(zhí)行的任務(wù)

也就是說,在當(dāng)前task任務(wù)后,下一個task之前,在渲染之前

所以它的響應(yīng)速度相比setTimeout(setTimeout是task)會更快,因為無需等渲染

也就是說,在某一個macrotask執(zhí)行完后,就會將在它執(zhí)行期間產(chǎn)生的所有microtask都執(zhí)行完畢(在渲染前)

分別很么樣的場景會形成macrotask和microtask呢?

macrotask:主代碼塊,setTimeout,setInterval等(可以看到,事件隊列中的每一個事件都是一個macrotask)

microtask:Promise,process.nextTick等

再根據(jù)線程來理解下:

macrotask中的事件都是放在一個事件隊列中的,而這個隊列由 事件觸發(fā)線程 維護

microtask中的所有微任務(wù)都是添加到微任務(wù)隊列(Job Queues)中,等待當(dāng)前macrotask執(zhí)行完畢后執(zhí)行,而這個隊列由 JS引擎線程維護 (這點由自己理解+推測得出,因為它是在主線程下無縫執(zhí)行的)

所以,總結(jié)下運行機制:

執(zhí)行一個宏任務(wù)(棧中沒有就從事件隊列中獲取)

執(zhí)行過程中如果遇到微任務(wù),就將它添加到微任務(wù)的任務(wù)隊列中

宏任務(wù)執(zhí)行完畢后,立即執(zhí)行當(dāng)前微任務(wù)隊列中的所有微任務(wù)(依次執(zhí)行)

當(dāng)前宏任務(wù)執(zhí)行完畢,開始檢查渲染,然后GUI線程接管渲染

渲染完畢后,JS線程繼續(xù)接管,開始下一個宏任務(wù)(從事件隊列中獲取)

如圖:

從瀏覽器多進程到JS單線程,JS運行機制最全面的一次梳理

另外,請注意下 Promise 的 polyfill 與官方版本的區(qū)別:

官方版本中,是標(biāo)準(zhǔn)的microtask形式

polyfill,一般都是通過setTimeout模擬的,所以是macrotask形式(目前沒見過有能直接模擬microtask,如果確實有,后續(xù)會修改這部分)

請?zhí)貏e注意這兩點區(qū)別

注意,有一些瀏覽器執(zhí)行結(jié)果不一樣(因為它們可能把microtask當(dāng)成macrotask來執(zhí)行了), 但是為了簡單,這里不描述一些不標(biāo)準(zhǔn)的瀏覽器下的場景(但記住,有些瀏覽器可能并不標(biāo)準(zhǔn))

寫在最后的話

看到這里,不知道對JS的運行機制是不是更加理解了,從頭到尾梳理,而不是就某一個碎片化知識應(yīng)該是會更清晰的吧?

同時,也應(yīng)該注意到了JS根本就沒有想象的那么簡單,前端的知識也是無窮無盡,層出不窮的概念、N多易忘的知識點、各式各樣的框架、 底層原理方面也是可以無限的往下深挖,然后你就會發(fā)現(xiàn),你知道的太少了。。。

另外,本文也打算先告一段落,其它的,如JS詞法解析,可執(zhí)行上下文以及VO等概念就不繼續(xù)在本文中寫了,后續(xù)可以考慮另開新的文章。

最后,喜歡的話,就請給個贊吧!

附錄 博客

初次發(fā)布 2018.01.21 于我個人博客上面

http://www.dailichun.com/2018/01/21/js_singlethread_eventloop.html

參考資料

https://www.cnblogs.com/lhb25/p/how-browsers-work.html

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

https://segmentfault.com/p/1210000012780980

http://blog.csdn.net/u013510838/article/details/55211033

http://blog.csdn.net/Steward2011/article/details/51319298

http://www.imweb.io/topic/58e3bfa845e5c13468f567d5

https://segmentfault.com/a/1190000008015671

https://juejin.im/post/5a4ed917f265da3e317df515

http://www.cnblogs.com/iovec/p/7904416.html

https://www.cnblogs.com/wyaocn/p/5761163.html

http://www.ruanyifeng.com/blog/2014/10/event-loop.html#comment-text

來自:https://dailc.github.io/2018/01/21/js_singlethread_eventloop.html

標(biāo)簽: JavaScript
主站蜘蛛池模板: 久久首页 | 中字精品 | www.色94色.com | 一区二区三区四区日韩 | 日本一区二区三区免费观看 | 国产精品永久免费 | 亚洲成人日韩 | 欧美人牲| 国产黄色大片 | 色综合二区 | 黄色片网站在线观看 | 免费黄网视频 | 一区二区三区视频免费看 | 性高湖久久久久久久久 | 国产亚洲精品v | 日日干夜夜操 | 久久久久久亚洲国产 | 成人免费视频网站在线看 | 黄色91在线 | 成人黄页在线观看 | 日韩欧美中文 | 国产精品综合 | 久草热8精品视频在线观看 黄色片网站视频 | 9191在线| 国产在线精品一区二区三区 | 久久99深爱久久99精品 | 免费成人在线观看视频 | 日本久久精品 | 另类免费视频 | 在线观看精品视频网站 | 久久精品视频一区 | 亚洲视频在线观看网址 | 激情一区二区 | 越南性xxxx精品hd | 2019天天干夜夜操 | 在线观看免费黄色 | 久久精品国产99国产 | 国产午夜精品一区二区三区嫩草 | 日产久久| 色综合色综合 | 欧美一级免费 | 视频一区二区三区免费观看 | 色黄网站| 国产成人在线一区二区 | 香蕉久久夜色精品国产使用方法 | 91免费看| 日韩精品www | 亚洲第一av网站 | 精品久久网 | 国产偷录视频叫床高潮对白 | 亚洲视频在线观看免费 | 精品国产欧美一区二区三区成人 | 国产一区二区三区四区在线观看 | 欧美区视频 | 三级黄色在线视频 | 九九热免费看 | 91一级| 国产视频福利一区 | 中文字幕一区二区在线观看 | 中文字幕二区 | 婷婷精品| 波多野结衣一区二区三区四区 | 偷拍自拍第一页 | 色天天天天色 | 人人做人人澡人人爽欧美 | 日韩成人影院 | 日韩一区二区不卡 | 欧美性v | 色爽女人免费 | а_天堂中文最新版地址 | 成av在线 | 日韩欧美国产一区二区 | 国产中文字幕一区 | 日日视频 | 中文字幕精品一区二区三区精品 | 免费看黄色一级视频 | 午夜精品在线 | 成人影 | 久久综合狠狠综合久久 | 午夜精选视频 | 国产精品久久久久久久久大全 | 91久久久久久久久久久久久久久久 | 久久精品一级 | 91精品国产综合久久国产大片 | 黄色一级在线观看 | 亚洲 精品 综合 精品 自拍 | 1000部精品久久久久久久久 | 久久九 | 天天干天天摸 | 亚洲视频在线观看视频 | 久草在线高清 | 精品亚洲一区二区 | 国产免费久久 | 欧美一二三区 | 精品视频久久 | 91精品国产综合久久婷婷香蕉 | 日本中文在线 | 不卡久久| 正在播放国产一区 | 日韩成人影院 | 久久久久999 | 四虎影院免费看 | av大片 | 国产成人一区二区三区 | 亚洲一区中文 | 欧美在线视频一区二区 | 国产欧美视频在线 | 午夜精品久久久久久久白皮肤 | 国产亚洲二区 | 日本在线观看一区二区 | 五月激情六月婷婷 | 亚洲国产精品一区 | www在线观看国产 | 日韩午夜av| 国产片淫级awww | 香蕉大人久久国产成人av | 黑人巨大精品欧美一区免费视频 | 免费欧美一级 | 一级毛片观看 | 亚洲综合视频一区 | 国产一区二区黑人欧美xxxx | 山岸逢花在线观看 | 在线观看一区 | 久久久国产精品 | 久久成人免费视频 | 在线成人www免费观看视频 | 亚洲 成人 av | 中文成人在线 | 日本黄色a级 | 91精品入口蜜桃 | 国产成人精品免费视频 | 后人极品翘臀美女在线播放 | 在线日韩视频 | 国产精品美女www爽爽爽动态图 | 精品九九九| 成人免费在线播放 | 国产精品久久久久久吹潮 | 成人免费共享视频 | www.国产.com| 久久99精品久久久久久 | 精品国产一区二区三区成人影院 | 国产精品久久久久久久久久免费 | 婷婷色国产偷v国产偷v小说 | 在线日韩欧美 | 国产中文一区 | 免费观看羞羞视频网站 | 日韩欧美在线观看一区二区三区 | 一区二区日韩视频 | 国产精品18hdxxxⅹ在线 | 久草 在线 | 国产精品人人做人人爽 | 山外人精品 | 日韩av入口 | a级在线免费 | 特级av | 看a网址| 日韩精品一区二区在线观看 | av福利在线观看 | 九九视频这里只有精品 | 精品在线一区二区三区 | 日韩中文字幕在线视频 | 亚洲自拍一区在线 | 91成人免费视频 | 黄色一级毛片 | 欧美一区国产一区 | 国产成人精品一区二区三区视频 | 国产精品久久久久久久久免费高清 | 欧美小电影 | 精品亚洲一区二区三区四区五区 | 久久小视频 | 亚洲人人 | 欧美 亚洲 另类 激情 另类 | 国产精品久久一区 | 欧美日韩中文字幕 | 一区二区三区四区在线视频 | 国产一区二区三区在线免费观看 | 黄在线看 | 91视频在线观看 | 一区二区三区在线播放 | av在线免费播放 | 日本手机在线视频 | 日本成人片网站 | 亚洲777 | 欧美日韩国产一区二区三区 | 凹凸日日摸日日碰夜夜爽孕妇 | www精品| 国产精品三级视频 | 一级免费视频 | 夜夜爽网址 | 国产精品午夜在线观看 | 亚洲成人免费视频在线观看 | 日韩久久久久久 | 久久久精品国产 | 国产乱a视频在线 | 国产一区二区三区久久久 | 日本a网| 日韩精品www | 国产精品久久久久久久久小说 | 99视频免费观看 | 欧美性一区二区三区 | 99热欧美 | 日韩在线欧美 | 色在线免费视频 | 国产精品久久久久久亚洲调教 | 欧美成人伊人 | 久久91av| 五月婷婷狠狠爱 | 欧美午夜视频 | 国产精品久久久久久久久久三级 | 亚洲精品久久久久久久久久久 | 一级片在线观看 | 91久久久久久久久 | 91视频网址 | 精品日韩中文字幕 | 欧美色综合天天久久综合精品 | 精品免费国产一区二区三区 | 久久一区二区三 | 亚洲视频免费网站 | 青青久久av北条麻妃海外网 | 成人精品在线观看 | 亚洲免费视频在线 | 中文字幕乱码一区二区三区 | 国产亚洲精品久久久久动 | 国产a久久精品一区二区三区 | 色花av | 成人精品视频一区二区三区 | 成人性生交大片免费看中文带字幕 | 日韩中文字幕在线视频 | 亚洲狠狠爱一区二区三区 | 欧美精品影院 | 国产不卡在线观看 | 成人做爰9片免费视频 | 中文在线一区二区 | 在线观看一级片 | 日韩免费高清视频 | 欧美一级二级视频 | 亚洲成人激情在线观看 | 日本精品在线观看 | 午夜影晥| 久久久久国产一区二区三区 | 日日撸| 1区2区3区视频 | 色久视频| 国产精品人人做人人爽 | av在线精品 | 国产精品亚洲欧美日韩一区在线 | 国产麻豆乱码精品一区二区三区 | 在线视频一区二区三区 | 久久porn | 亚洲精品二区 | 黄a在线 | 久久久久无码国产精品一区 | av网站免费观看 | 色偷偷噜噜噜亚洲男人 | 一区视频在线 | 久久精品欧美一区二区三区麻豆 | 日韩视频一区 | 网址av | 亚洲精品久久久久久久久久久久久 | av资源中文在线天堂 | 欧美一区二区在线视频 | 精品视频成人 | 国产精品久久久久久一区二区三区 | 久久久久久久99精品免费观看 | 免费在线日韩 | 色一情一乱一伦一区二区三区 | av国产精品毛片一区二区小说 | 在线亚洲观看 | a久久 | 亚洲日日操 | 免费色在线 | 人人玩人人添人人澡97 | 天天射欧美 | 精品国产乱码简爱久久久久久 | 久久成人国产精品 | 夜夜av | 久久精品久久精品国产大片 | 欧美日韩精品一区二区三区在线观看 | 天天干天天操天天干 | 成人在线看片 | 91精品久久久久久久久久入口 | 国产精品视频99 | 日本久久99 | 久久精品一区二区三区四区 | 日韩激情一区二区 | 亚洲欧美第一页 | 亚洲不卡视频在线 | 国外成人在线视频网站 | 久久久av| 成人伊人网 | 狠狠入ady亚洲精品经典电影 | 国产高清精品在线 | 美女一区| 成人av在线播放 | 一级片免费在线 | 国产精品日韩欧美 | 99久久久99久久国产片鸭王 | 成年人在线观看 | 黄色网在线 | 91在线免费看 | 日韩国产 | 亚洲男人av| 亚洲欧美一区二区三区在线 | 亚洲一区视频在线播放 | 国产日韩免费视频 | 在线国产一区二区 | 四虎com| 男女视频在线观看 | 国产在线中文字幕 | 亚洲欧美国产一区二区 | 四影虎影www4hu23cmo | 国产 日韩 欧美 中文 在线播放 | 亚洲不卡在线观看 | 97伦理网 | 97夜夜操| 成人a在线视频免费观看 | 精品久久中文字幕 | 久久99精品久久久噜噜最新章节 | 色综合视频| av一级久久 | 欧美日本久久 | 亚洲精品视频在线看 | 中文字幕第100页 | 午夜精品亚洲日日做天天做 | 国产天堂网 | 黄色精品网站 | 精品无人乱码一区二区三区 | 精品亚洲国产成av人片传媒 | 久久男人天堂 | 青青草免费在线 | 在线视频成人永久免费 | 日韩第一区 | 亚洲毛片网站 | av香港经典三级级 在线 | 成人在线网| 国内精品久久久久久中文字幕 | 成年人在线看片 | 农村少妇kkkk7777 | 国产黄色在线观看 | 日韩精品一区二区在线观看 | 亚洲精品一区二区在线 | 国产欧美在线观看 | 精品欧美一区二区三区久久久小说 | 日日操视频 | 欧美精品在线免费观看 | 曰韩毛片 | 久久99精品国产麻豆婷婷洗澡 | 国产毛片a级 | 另类亚洲专区 | 欧美在线视频三区 | 精品一区二区三区在线视频 | 日韩午夜在线 | 日韩综合网| 久久爱www. | 丁香久久| 亚洲精品国产综合 | 国产香蕉视频在线播放 | 亚洲精品国产电影 | 九九热这里都是精品 | 吴梦梦到粉丝家实战华中在线观看 | 在线观看免费视频亚洲 | 91一区二区 | 成人在线免费网站 | 中文字幕在线观看 | 亚洲乱码在线 | 美女国产精品 | 男人亚洲天堂网 | 男女羞羞视频在线观看 | 免费亚洲网站 | 日本精品免费 | 精品国产仑片一区二区三区 | 91精品国产综合久久久久 | 日韩视频一区 | 视频一区在线观看 | 久久这里只有精品首页 | 亚洲成人精品在线观看 | 国产一区二区三区在线免费观看 | 欧美在线 | 亚洲 | 夜夜操com | 国产精品毛片久久久久久久 | 日韩欧美在线观看一区 | 伊人av超碰久久久麻豆 | 亚洲精品一区二区三区 | 黄色国产视频 | 夜夜草天天干 | 欧美一级二级三级视频 | 天天久久 | 天堂精品久久 | 97精品国产 | 欧美视频免费 | 黄色片免费在线观看 | 中文字幕亚洲一区 | 久久视频在线 | 中文字幕一区二区三区四区不卡 | 日韩一区二区在线观看 | 欧美xxxx片 | 国产精品久久久久久久久费观看 | 午夜伦理影院 | 日本一区二区成人 | 欧美性久久 | 日韩中文字幕免费在线播放 | 奇米影视奇米色777欧美 | 凹凸日日摸日日碰夜夜爽孕妇 | 四虎成人在线播放 | 欧美黑人一级爽快片淫片高清 | 91麻豆精品国产91久久久更新资源速度超快 | 国产自产才c区 | 久草免费在线视频 | 亚洲成人伦理 | 亚洲社区在线 | 国产高清视频一区二区 | 成人av免费 | 一区二区精品在线 | 欧美精品在线看 | 日韩成人三级 | 婷色综合| 国产精品视频播放 | 中文字幕一区二区三区不卡 | 国产精品1 | 亚洲成人激情在线观看 | 黄色毛片在线看 | 成人免费大片黄在线播放 | 一区二区亚洲 | 中文字幕第二页 | 精品日韩一区二区 | 国产一区二区在线播放 | 91人人看 | 一区二区三区四区免费观看 | 日韩av黄色 | 中文字幕亚洲区 | 亚洲国产成人在线观看 | 日韩无在线 | 91精品视频一区 | 欧美一区久久 | 亚洲国产高清高潮精品美女 | 欧美一级片毛片免费观看视频 | 久久综合成人精品亚洲另类欧美 | 高清成人| 精品日韩| 思热99re视热频这里只精品 | 美女国产精品 | 在线观看免费视频黄 | 中文字幕日韩欧美一区二区三区 | 成人二区 | 成人a网 | 中国一级特黄毛片大片 | 欧美另类一区二区 | 精品国产999 | 99成人在线视频 | 免费av在线| 亚洲精品久久久久久一区二区 | 日韩欧美国产精品 | 色视频网站在线观看 | 99免费视频 | 色综合网址 | 蜜桃免费视频 | 亚洲一区二区三区四区五区中文 | 成人精品一区二区三区中文字幕 | 国产精品手机在线 | 午夜精品一区二区三区免费视频 | 中文字幕精品一区二区三区精品 | 久久精品视 | 精品久久久久久 | 久久精品无码一区二区日韩av | 国产精品视频久久久 | 高清视频一区 | 黄色一级免费大片 | 美女黄视频网站 | 亚洲成人一区 | 海外中文字幕在线观看 | 精品视频一区在线观看 | 国产区一区 | 亚洲男人天堂网 | 欧美极品视频 | 欧洲亚洲视频 | 日韩欧美专区 | 精品欧美乱码久久久久久 | 三级成人在线 | 亚洲精品一区国产精品 | 国产一区91| 亚洲午夜精品一区二区三区 | 欧美自拍三区 | 亚洲欧洲无码一区二区三区 | 亚洲久草视频 | 亚洲久草 | 一区二区久久 | 欧美性网 | 国产高清一级 | 中文乱码一区 | 天堂欧美城网站 | 激情六月婷 | 91精品一区二区三区久久久久 | 国产美女自拍视频 | 日韩在线免费电影 | 山岸逢花在线观看无删减 | 男女小网站 | 久久av资源 | 亚洲一区精品视频 | 日本在线播放 | 成人精品鲁一区一区二区 | 精品成人免费一区二区在线播放 | 欧美成人一区二区 | 亚洲视频一区在线 | 大象视频成人在线观看 | 日本高清无卡码一区二区久久 | 欧美视频精品 | 日韩中文字幕一区二区高清99 | 看毛片的网站 | 亚洲人免费视频 | 91免费在线看 | 日韩精品一区二区三区在线 | 日韩专区一区二区三区 | 中文字幕日韩欧美一区二区三区 | 九九热在线免费视频 | 亚洲电影在线 | 亚洲aaa在线观看 | 国产一区中文字幕 | 日本一区二区成人 | 天天操免费 | 国产精品一区二区三区在线 | 在线观看91 | 国产成人久久精品麻豆二区 | 亚洲www视频 | 噜噜噜在线观看免费视频日本 | 亚洲精品在线播放 | 久久久久网站 | 精品亚洲一区二区三区 | 色婷婷国产精品 | 日韩一区二区三区在线 | 99久久久久久 | 九九久久久| 久久婷婷欧美 | 91丨九色丨国产 | 国产成人久久精品一区二区三区 | 欧美视频综合 | 国产精品久久久久久久一区探花 | 国产在线精品一区二区三区 | 国产亚洲二区 | 欧美综合国产精品久久丁香 | 日本成人久久 | 一区二区三区四区av | 欧美日韩视频在线播放 | 国产另类ts人妖一区二区 | 成人欧美一区二区三区 | 少妇一区二区三区 | 日韩欧美在线免费观看 | 欧美三级在线播放 | 亚洲天堂久久 | 韩国精品免费视频 | 国产日韩在线播放 | 国产91久久精品一区二区 | 亚洲一区二区三区四区在线观看 | 精品一区二区在线观看 | 国产精品揄拍一区二区久久国内亚洲精 | 久久久毛片 | 日本色综合| av解说在线精品 | 国产在线91| 国产成人在线播放 | 狠狠av| 国产色网| 成人在线观看免费视频 | 国产精品成人国产乱一区 | 综合久久99 | 久久国产精品免费一区二区三区 | 午夜精品久久久久久久白皮肤 | www,四虎| 欧美综合久久 | 欧美日韩国产在线 | 亚洲国产精品久久久 | 亚洲精品成人久久久 | 欧美在线一区二区 | 日韩国产在线 | 91观看| 久热精品视频 | 久久99国产伦子精品免费 | 成人免费小视频 | 成人免费福利 | 欧美日本韩国一区二区 | 欧美全黄 | 在线高清av | 亚洲欧美激情在线 | 午夜在线 | 亚洲成av人片一区二区三区 | 成人看片在线 | 成人欧美一区二区三区白人 | 国产人成精品一区二区三 | 亚洲欧美综合 | 亚洲欧美一 | 成人免费视频网站在线观看 | 日韩6699人妻熟女毛片 | 激情欧美日韩一区二区 | 久久精品伊人 | 欧美精品亚洲 | 国产永久免费 | 久久艹久久 | 蜜桃精品久久久久久久免费影院 | 国产精品欧美一区二区三区 | 成人激情视频在线观看 | 另类sb东北妇女av | 国产精品久久久久久久久久10秀 | 久久精品店| 国产美女网站视频 | 日韩在线精品视频 | 日韩毛片在线观看 | 亚洲精品久久 | 免费毛片视频 | 成人欧美一区二区三区在线播放 | 99re在线 | 欧美成年黄网站色视频 | 亚州成人 | 日韩亚洲| 日韩五月| 91精品久久久久久9s密挑 | 91伦理片 |