成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

淺談瀏覽器多進(jìn)程與JS線程

Juven / 688人閱讀

摘要:引言一直對(duì)瀏覽器的進(jìn)程線程的運(yùn)行一無(wú)所知,經(jīng)過(guò)一次的刷刷刷相關(guān)的博客之后,對(duì)其有了初步的了解,是時(shí)候該總結(jié)一波了。瀏覽器內(nèi)的進(jìn)程知道了進(jìn)程與線程之間的關(guān)系之后,下面是瀏覽器與進(jìn)程的關(guān)系了。

引言

一直對(duì)瀏覽器的進(jìn)程、線程的運(yùn)行一無(wú)所知,經(jīng)過(guò)一次的刷刷刷相關(guān)的博客之后,對(duì)其有了初步的了解,是時(shí)候該總結(jié)一波了。

進(jìn)程、線程之間的關(guān)系

一個(gè)進(jìn)程有一個(gè)或多個(gè)線程,線程之間共同完成進(jìn)程分配下來(lái)的任務(wù)。打個(gè)比方:

假如進(jìn)程是一個(gè)工廠,工廠有它的獨(dú)立的資源

工廠之間相互獨(dú)立

線程是工廠中的工人,多個(gè)工人協(xié)作完成任務(wù)

工廠內(nèi)有一個(gè)或多個(gè)工人

工人之間共享空間

再完善完善概念:

工廠的資源 -> 系統(tǒng)分配的內(nèi)存(獨(dú)立的一塊內(nèi)存)

工廠之間的相互獨(dú)立 -> 進(jìn)程之間相互獨(dú)立

多個(gè)工人協(xié)作完成任務(wù) -> 多個(gè)線程在進(jìn)程中協(xié)作完成任務(wù)

工廠內(nèi)有一個(gè)或多個(gè)工人 -> 一個(gè)進(jìn)程由一個(gè)或多個(gè)線程組成

工人之間共享空間 -> 同一進(jìn)程下的各個(gè)線程之間共享程序的內(nèi)存空間(包括代碼段、數(shù)據(jù)集、堆等)

進(jìn)程是cpu資源分配的最小單位(是能擁有資源和獨(dú)立運(yùn)行的最小單位),線程是cpu調(diào)度的最小單位(線程是建立在進(jìn)程的基礎(chǔ)上的一次程序運(yùn)行單位)。

瀏覽器內(nèi)的進(jìn)程

知道了進(jìn)程與線程之間的關(guān)系之后,下面是瀏覽器與進(jìn)程的關(guān)系了。首先,瀏覽器是多進(jìn)程的,之所以瀏覽器能夠運(yùn)行,是因?yàn)橄到y(tǒng)給瀏覽器分配了資源,如cpu、內(nèi)存,簡(jiǎn)單的說(shuō)就是,瀏覽器每打開(kāi)一個(gè)標(biāo)簽頁(yè),就相當(dāng)于創(chuàng)建了一個(gè)獨(dú)立的瀏覽器進(jìn)程。例如我們查看chrome里面的任務(wù)管理器。

注意: 在這里瀏覽器應(yīng)該也有自己的優(yōu)化機(jī)制,有時(shí)候打開(kāi)多個(gè)tab頁(yè)后,可以在Chrome任務(wù)管理器中看到,有些進(jìn)程被合并了(譬如打開(kāi)多個(gè)空白標(biāo)簽頁(yè)后,會(huì)發(fā)現(xiàn)多個(gè)空白標(biāo)簽頁(yè)被合并成了一個(gè)進(jìn)程),所以每一個(gè)Tab標(biāo)簽對(duì)應(yīng)一個(gè)進(jìn)程并不一定是絕對(duì)的。

除了瀏覽器的標(biāo)簽頁(yè)進(jìn)程之外,瀏覽器還有一些其他進(jìn)程來(lái)輔助支撐標(biāo)簽頁(yè)的進(jìn)程,如下:
① Browser進(jìn)程:瀏覽器的主進(jìn)程(負(fù)責(zé)協(xié)調(diào)、主控),只有一個(gè)。作用有

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

負(fù)責(zé)各個(gè)頁(yè)面的管理,創(chuàng)建和銷毀其他進(jìn)程

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

② 第三方插件進(jìn)程:每種類型的插件對(duì)應(yīng)一個(gè)進(jìn)程,僅當(dāng)使用該插件時(shí)才創(chuàng)建
③ GPU進(jìn)程:最多一個(gè),用于3D繪制等
④ 瀏覽器渲染進(jìn)程(瀏覽器內(nèi)核),Renderer進(jìn)程,內(nèi)部是多線程的,也就是我們每個(gè)標(biāo)簽頁(yè)所擁有的進(jìn)程,互不影響,負(fù)責(zé)頁(yè)面渲染,腳本執(zhí)行,事件處理等

如下圖:

瀏覽器內(nèi)核

瀏覽器內(nèi)核,即我們的渲染進(jìn)程,有名Renderer進(jìn)程,我們頁(yè)面的渲染,js的執(zhí)行,事件的循環(huán)都在這一進(jìn)程內(nèi)進(jìn)行,也就是說(shuō),該進(jìn)程下面擁有著多個(gè)線程,靠著這些現(xiàn)成共同完成渲染任務(wù)。那么這些線程是什么呢,如下:

① 圖形用戶界面GUI渲染線程

負(fù)責(zé)渲染瀏覽器界面,包括解析HTML、CSS、構(gòu)建DOM樹(shù)、Render樹(shù)、布局與繪制等

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

② JS引擎線程

JS內(nèi)核,也稱JS引擎,負(fù)責(zé)處理執(zhí)行javascript腳本

等待任務(wù)隊(duì)列的任務(wù)的到來(lái),然后加以處理,瀏覽器無(wú)論什么時(shí)候都只有一個(gè)JS引擎在運(yùn)行JS程序

③ 事件觸發(fā)線程

聽(tīng)起來(lái)像JS的執(zhí)行,但是其實(shí)歸屬于瀏覽器,而不是JS引擎,用來(lái)控制時(shí)間循環(huán)(可以理解,JS引擎自己都忙不過(guò)來(lái),需要瀏覽器另開(kāi)線程協(xié)助)

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

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

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

④ 定時(shí)觸發(fā)器線程

setIntervalsetTimeout所在線程

定時(shí)計(jì)時(shí)器并不是由JS引擎計(jì)時(shí)的,因?yàn)槿绻鸍S引擎是單線程的,如果JS引擎處于堵塞狀態(tài),那會(huì)影響到計(jì)時(shí)的準(zhǔn)確

當(dāng)計(jì)時(shí)完成被觸發(fā),事件會(huì)被添加到事件隊(duì)列,等待JS引擎空閑了執(zhí)行

注意:W3C的HTML標(biāo)準(zhǔn)中規(guī)定,setTimeout中低與4ms的時(shí)間間隔算為4ms

⑤ 異步HTTP請(qǐng)求線程

在XMLHttpRequest在連接后新啟動(dòng)的一個(gè)線程

線程如果檢測(cè)到請(qǐng)求的狀態(tài)變更,如果設(shè)置有回調(diào)函數(shù),該線程會(huì)把回調(diào)函數(shù)添加到事件隊(duì)列,同理,等待JS引擎空閑了執(zhí)行

瀏覽器內(nèi)核,放圖加強(qiáng)記憶:

為什么JS引擎是單線程的

JavaScript作為一門客戶端的腳本語(yǔ)言,主要的任務(wù)是處理用戶的交互,而用戶的交互無(wú)非就是響應(yīng)DOM的增刪改,使用事件隊(duì)列的形式,一次事件循環(huán)只處理一個(gè)事件響應(yīng),使得腳本執(zhí)行相對(duì)連續(xù)。如果JS引擎被設(shè)計(jì)為多線程的,那么DOM之間必然會(huì)存在資源競(jìng)爭(zhēng),那么語(yǔ)言的實(shí)現(xiàn)會(huì)變得非常臃腫,在客戶端跑起來(lái),資源的消耗和性能將會(huì)是不太樂(lè)觀的,故設(shè)計(jì)為單線程的形式,并附加一些其他的線程來(lái)實(shí)現(xiàn)異步的形式,這樣運(yùn)行成本相對(duì)于使用JS多線程來(lái)說(shuō)降低了很多。

瀏覽器內(nèi)核中線程之間的關(guān)系 GUI渲染線程與JS引擎線程互斥

因?yàn)镴S引擎可以修改DOM樹(shù),那么如果JS引擎在執(zhí)行修改了DOM結(jié)構(gòu)的同時(shí),GUI線程也在渲染頁(yè)面,那么這樣就會(huì)導(dǎo)致渲染線程獲取的DOM的元素信息可能與JS引擎操作DOM后的結(jié)果不一致。為了防止這種現(xiàn)象,GUI線程與JS線程需要設(shè)計(jì)為互斥關(guān)系,當(dāng)JS引擎執(zhí)行的時(shí)候,GUI線程需要被凍結(jié),但是GUI的渲染會(huì)被保存在一個(gè)隊(duì)列當(dāng)中,等待JS引擎空閑的時(shí)候執(zhí)行渲染。
由此也可以推出,如果JS引擎正在進(jìn)行CPU密集型計(jì)算,那么JS引擎將會(huì)阻塞,長(zhǎng)時(shí)間不空閑,導(dǎo)致渲染進(jìn)程一直不能執(zhí)行渲染,頁(yè)面就會(huì)看起來(lái)卡頓卡頓的,渲染不連貫,所以,要盡量避免JS執(zhí)行時(shí)間過(guò)長(zhǎng)。

JS引擎線程與事件觸發(fā)線程、定時(shí)觸發(fā)器線程、異步HTTP請(qǐng)求線程

事件觸發(fā)線程、定時(shí)觸發(fā)器線程、異步HTTP請(qǐng)求線程三個(gè)線程有一個(gè)共同點(diǎn),那就是使用回調(diào)函數(shù)的形式,當(dāng)滿足了特定的條件,這些回調(diào)函數(shù)會(huì)被執(zhí)行。這些回調(diào)函數(shù)被瀏覽器內(nèi)核理解成事件,在瀏覽器內(nèi)核中擁有一個(gè)事件隊(duì)列,這三個(gè)線程當(dāng)滿足了內(nèi)部特定的條件,會(huì)將這些回調(diào)函數(shù)添加到事件隊(duì)列中,等待JS引擎空閑執(zhí)行。例如異步HTTP請(qǐng)求線程,線程如果檢測(cè)到請(qǐng)求的狀態(tài)變更,如果設(shè)置有回調(diào)函數(shù),回調(diào)函數(shù)會(huì)被添加事件隊(duì)列中,等待JS引擎空閑了執(zhí)行。
但是,JS引擎對(duì)事件隊(duì)列(宏任務(wù))與JS引擎內(nèi)的任務(wù)(微任務(wù))執(zhí)行存在著先后循序,當(dāng)每執(zhí)行完一個(gè)事件隊(duì)列的時(shí)間,JS引擎會(huì)檢測(cè)內(nèi)部是否有未執(zhí)行的任務(wù),如果有,將會(huì)優(yōu)先執(zhí)行(微任務(wù))。

WebWorker

因?yàn)镴S引擎是單線程的,當(dāng)JS執(zhí)行時(shí)間過(guò)長(zhǎng)會(huì)頁(yè)面阻塞,那么JS就真的對(duì)CPU密集型計(jì)算無(wú)能為力么?

所以,后來(lái)HTML5中支持了 Web Worker。

來(lái)自MDN的官方解釋

Web Workers 使得一個(gè)Web應(yīng)用程序可以在與主執(zhí)行線程分離的后臺(tái)線程中運(yùn)行一個(gè)腳本操作。這樣做的好處是可以在一個(gè)多帶帶的線程中執(zhí)行費(fèi)時(shí)的處理任務(wù),從而允許主(通常是UI)線程運(yùn)行而不被阻塞/放慢。

注意點(diǎn):

WebWorker可以想瀏覽器申請(qǐng)一個(gè)子線程,該子線程服務(wù)于主線程,完全受主線程控制。

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

所以,如果需要進(jìn)行一些高耗時(shí)的計(jì)算時(shí),可以多帶帶開(kāi)啟一個(gè)WebWorker線程,這樣不管這個(gè)WebWorker子線程怎么密集計(jì)算、怎么阻塞,都不會(huì)影響JS引擎主線程,只需要等計(jì)算結(jié)束,將結(jié)果通過(guò)postMessage傳輸給主線程就可以了。

另外,還有個(gè)東西叫 SharedWorker,與WebWorker在概念上所不同。

WebWorker 只屬于某一個(gè)頁(yè)面,不會(huì)和其他標(biāo)簽頁(yè)的Renderer進(jìn)程共享,WebWorker是屬于Renderer進(jìn)程創(chuàng)建的進(jìn)程。

SharedWorker 是由瀏覽器多帶帶創(chuàng)建的進(jìn)程來(lái)運(yùn)行的JS程序,它被所有的Renderer進(jìn)程所共享,在瀏覽器中,最多只能存在一個(gè)SharedWorker進(jìn)程。

SharedWorker由進(jìn)程管理,WebWorker是某一個(gè)Renderer進(jìn)程下的線程。

瀏覽器的渲染流程

每個(gè)瀏覽器內(nèi)核的渲染流程不一樣,下面我們主要以webkit為主。
首先是渲染的前奏:

瀏覽器輸入url,瀏覽器主進(jìn)程接管,開(kāi)了一個(gè)下載線程

然后進(jìn)行HTTP請(qǐng)求(DNS查詢、IP尋址等等),等待響應(yīng),開(kāi)始下載響應(yīng)報(bào)文。

將下載完的內(nèi)容轉(zhuǎn)交給Renderer進(jìn)程管理

開(kāi)始渲染...

在說(shuō)渲染之前,需要理解一些概念:

DOM Tree: 瀏覽器將HTML解析成樹(shù)形的數(shù)據(jù)結(jié)構(gòu)。

CSS Rule Tree:瀏覽器將CSS解析成樹(shù)形的數(shù)據(jù)結(jié)構(gòu)。

Render Tree:DOM樹(shù)和CSS規(guī)則樹(shù)合并后生產(chǎn)Render樹(shù)。

layout:有了Render Tree,瀏覽器已經(jīng)能知道網(wǎng)頁(yè)中有哪些節(jié)點(diǎn)、各個(gè)節(jié)點(diǎn)的CSS定義以及他們的從屬關(guān)系,從而去計(jì)算出每個(gè)節(jié)點(diǎn)在屏幕中的位置。

painting: 按照算出來(lái)的規(guī)則,通過(guò)顯卡,把內(nèi)容畫(huà)到屏幕上。

reflow(回流):當(dāng)瀏覽器發(fā)現(xiàn)某個(gè)部分發(fā)生了點(diǎn)變化影響了布局,需要倒回去重新渲染,內(nèi)行稱這個(gè)回退的過(guò)程叫 reflow。reflow 會(huì)從 這個(gè) root frame 開(kāi)始遞歸往下,依次計(jì)算所有的結(jié)點(diǎn)幾何尺寸和位置。reflow 幾乎是無(wú)法避免的。現(xiàn)在界面上流行的一些效果,比如樹(shù)狀目錄的折疊、展開(kāi)(實(shí)質(zhì)上是元素的顯 示與隱藏)等,都將引起瀏覽器的 reflow。鼠標(biāo)滑過(guò)、點(diǎn)擊……只要這些行為引起了頁(yè)面上某些元素的占位面積、定位方式、邊距等屬性的變化,都會(huì)引起它內(nèi)部、周圍甚至整個(gè)頁(yè)面的重新渲 染。通常我們都無(wú)法預(yù)估瀏覽器到底會(huì) reflow 哪一部分的代碼,它們都彼此相互影響著。

repaint(重繪):改變某個(gè)元素的背景色、文字顏色、邊框顏色等等不影響它周圍或內(nèi)部布局的屬性時(shí),屏幕的一部分要重畫(huà),但是元素的幾何尺寸沒(méi)有變。

注意:display:none的節(jié)點(diǎn)不會(huì)被加入Render Tree,而visibility: hidden則會(huì),所以display:none會(huì)觸發(fā)reflow,visibility: hidden會(huì)觸發(fā)repaint。

瀏覽器內(nèi)核拿到響應(yīng)報(bào)文之后,渲染大概分為以下步驟

解析html生產(chǎn)DOM樹(shù)。

解析CSS規(guī)則。

根據(jù)DOM Tree和CSS Tree生成Render Tree。

根據(jù)Render樹(shù)進(jìn)行l(wèi)ayout,負(fù)責(zé)各個(gè)元素節(jié)點(diǎn)的尺寸、位置計(jì)算。

繪制Render樹(shù)(painting),繪制頁(yè)面像素信息。

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

詳細(xì)步驟略去,大概步驟如下,渲染完畢后JS引擎開(kāi)始執(zhí)行load事件,繪制流程見(jiàn)下圖。

由圖中可以看出,css在加載過(guò)程中不會(huì)影響到DOM樹(shù)的生成,但是會(huì)影響到Render樹(shù)的生成,進(jìn)而影響到layout,所以一般來(lái)說(shuō),style的link標(biāo)簽需要盡量放在head里面,因?yàn)樵诮馕鯠OM樹(shù)的時(shí)候是自上而下的,而css樣式又是通過(guò)異步加載的,這樣的話,解析DOM樹(shù)下的body節(jié)點(diǎn)和加載css樣式能盡可能的并行,加快Render樹(shù)的生成的速度,當(dāng)然,如果css是通過(guò)js動(dòng)態(tài)添加進(jìn)來(lái)的,會(huì)引起頁(yè)面的重繪或重新布局。
從有html標(biāo)準(zhǔn)以來(lái)到目前為止(2017年5月),標(biāo)準(zhǔn)一直是規(guī)定style元素不應(yīng)出現(xiàn)在body元素中。

前面提到了load事件,那么與DOMContentLoaded事件有什么分別。

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

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

順序是:DOMContentLoaded -> load

最后

寫(xiě)到這里,總結(jié)了也有不少的內(nèi)容,也對(duì)瀏覽器多線程、JS引擎有所了解,后面打算在看看JS的運(yùn)行機(jī)制。前端知識(shí)也是無(wú)窮無(wú)盡,數(shù)不清的概念與無(wú)數(shù)個(gè)易忘的知識(shí)、各種框架原理,學(xué)來(lái)學(xué)去,還是發(fā)現(xiàn)自己知道得太少了。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/107120.html

相關(guān)文章

  • 淺談 JavaScript 運(yùn)行機(jī)制

    摘要:以多線程的形式,允許單個(gè)任務(wù)分成不同的部分進(jìn)行運(yùn)行。提供協(xié)調(diào)機(jī)制,一方面防止進(jìn)程之間和線程之間產(chǎn)生沖突,另一方面允許進(jìn)程之間和線程之間共享資源。主線程會(huì)不斷的重復(fù)上訴過(guò)程。 眾所周知,js是單線程的,說(shuō)到線程,我們首先來(lái)仔細(xì)辨析一下線程和進(jìn)程的知識(shí)。 一、進(jìn)程與線程 阮一峰老師的一篇文章寫(xiě)的很好 cpu會(huì)給當(dāng)前進(jìn)程分配資源,進(jìn)程是資源分配的最小單位,進(jìn)程的資源會(huì)分配給線程使用,線程是C...

    URLOS 評(píng)論0 收藏0
  • 淺談HTML5 Web Worker

    摘要:事實(shí)上,瀏覽器內(nèi)部的運(yùn)行機(jī)制是,先將通信內(nèi)容串行化,然后把串行化后的字符串發(fā)給子線程,后者再將它還原。當(dāng)一個(gè)的文檔列表中的任何一個(gè)對(duì)象都是處于完全活動(dòng)狀態(tài)的時(shí)候,這個(gè)會(huì)被稱之為需要激活線程。 瀏覽器中的Web Worker 背景介紹 我們都知道JavaScript這個(gè)語(yǔ)言在執(zhí)行的時(shí)候是采用單線程進(jìn)行執(zhí)行的,也就是說(shuō)在同一時(shí)間只能做一件事,這也和這門語(yǔ)言有很大的關(guān)系,采用同步執(zhí)行的方式進(jìn)...

    Tecode 評(píng)論0 收藏0
  • 淺談線程

    摘要:線程被稱為輕量級(jí)進(jìn)程。在大多數(shù)操作系統(tǒng)中,線程都是最基本的調(diào)度單位。在多線程程序中,,還存在由于使用多線程而引入的其他問(wèn)題。由于多線程訪問(wèn)無(wú)狀態(tài)對(duì)象的行為不會(huì)影響到其他線程中操作的正確性,因此無(wú)狀態(tài)對(duì)象一定是線程安全的。 概述 最近遇到了些并發(fā)的問(wèn)題,恰巧也有朋友問(wèn)我類似的問(wèn)題,無(wú)奈并發(fā)基礎(chǔ)知識(shí)過(guò)弱,只大概了解使用一些同步機(jī)制和并發(fā)工具包類,沒(méi)有形成一個(gè)完整的知識(shí)體系,并不能給出一個(gè)良...

    Freeman 評(píng)論0 收藏0
  • 淺談Python線程

    摘要:進(jìn)程可創(chuàng)建多個(gè)線程來(lái)執(zhí)行同一程序的不同部分。就緒等待線程調(diào)度。運(yùn)行線程正常運(yùn)行阻塞暫停運(yùn)行,解除阻塞后進(jìn)入狀態(tài)重新等待調(diào)度。消亡線程方法執(zhí)行完畢返回或者異常終止。多線程多的情況下,依次執(zhí)行各線程的方法,前頭一個(gè)結(jié)束了才能執(zhí)行后面一個(gè)。 淺談Python多線程 作者簡(jiǎn)介: 姓名:黃志成(小黃)博客: 博客 線程 一.什么是線程? 操作系統(tǒng)原理相關(guān)的書(shū),基本都會(huì)提到一句很經(jīng)典的話: 進(jìn)程...

    zsirfs 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<