瀏覽器的運行機制—3.瀏覽器的渲染進程

重點來了,我們可以看到褐桌,上面提到了這么多的進程,那么象迎,對于普通的前端操作來說荧嵌,最終要的是什么呢?答案是渲染進程砾淌。因為頁面的渲染啦撮,JS的執(zhí)行,事件的觸發(fā)汪厨,都在這個進程內(nèi)進行的赃春。接下來重點分析這個進程。

之前講到過劫乱,進程一般是多線程的织中,忘了可以再復習下前面第一節(jié),進程和線程衷戈,那么瀏覽器的渲染進程又包括哪些線程狭吼。

1.渲染進程包括哪些線程

  1. GUI渲染線程
  • 負責渲染瀏覽器界面,解析HTML殖妇,CSS刁笙,構(gòu)建DOM樹和RenderObject樹,布局和繪制等。
  • 當界面需要重繪(Repaint)或由于某種操作引發(fā)回流(reflow)時疲吸,該線程就會執(zhí)行
  • 注意座每,GUI渲染線程與JS引擎線程是互斥的,當JS引擎執(zhí)行時GUI線程會被掛起(相當于被凍結(jié)了)摘悴,GUI更新會被保存在一個隊列中等到JS引擎空閑時立即被執(zhí)行峭梳。
  1. JS引擎線程(單線程)
  • 也稱為JS內(nèi)核,負責處理Javascript腳本程序烦租。(例如常常聽到的谷歌瀏覽器的V8引擎延赌,新版火狐的JaegerMonkey引擎等)
  • JS引擎線程負責解析Javascript腳本,運行代碼叉橱。
  • JS引擎一直等待著任務隊列中任務的到來挫以,然后加以處理,一個Tab頁(renderer進程)中無論什么時候都只有一個JS線程在運行JS程序
  • 同樣注意窃祝,GUI渲染線程與JS引擎線程是互斥的掐松,所以如果JS執(zhí)行的時間過長,這樣就會造成頁面的渲染不連貫粪小,導致頁面渲染加載阻塞大磺。
  1. 事件觸發(fā)線程
  • 歸屬于渲染進程而不是JS引擎,用來控制事件輪詢(可以理解探膊,JS引擎自己都忙不過來杠愧,需要瀏覽器另開線程協(xié)助)
  • 當JS引擎執(zhí)行代碼塊如鼠標點擊、AJAX異步請求等逞壁,會將對應任務添加到事件觸發(fā)線程中
  • 當對應的事件符合觸發(fā)條件被觸發(fā)時流济,該線程會把事件添加到待處理任務隊列的隊尾,等待JS引擎的處理
  • 注意腌闯,由于JS的單線程關(guān)系绳瘟,所以這些待處理隊列中的事件都得排隊等待JS引擎處理(當JS引擎空閑時才會去執(zhí)行)
  1. 定時觸發(fā)器線程

    • 定時器setInterval與setTimeout所在線程
    • 瀏覽器定時計數(shù)器并不是由JavaScript引擎計數(shù)的,(因為JavaScript引擎是單線程的, 如果任務隊列處于阻塞線程狀態(tài)就會影響記計時的準確)
    • 因此通過單獨線程來計時并觸發(fā)定時(計時完畢后,添加到事件隊列中姿骏,等待JS引擎空閑后執(zhí)行)
    • 注意糖声,W3C在HTML標準中規(guī)定,規(guī)定要求setTimeout中低于4ms的時間間隔算為4ms分瘦。
  2. 異步http請求線程

    • 用于處理請求XMLHttpRequest蘸泻,在連接后是通過瀏覽器新開一個線程請求。如ajax擅腰,是瀏覽器新開一個http線程
    • 將檢測到狀態(tài)變更(如ajax返回結(jié)果)時蟋恬,如果設置有回調(diào)函數(shù),異步線程就產(chǎn)生狀態(tài)變更事件趁冈,將這個回調(diào)再放入js引擎線程的事件隊列中歼争。再由JavaScript引擎執(zhí)行拜马。


      2084336019-5a65972413011.png

知道了這幾個線程,那么通過這幾個線程沐绒,js是怎么執(zhí)行的呢俩莽?

2.渲染進程中的線程之間的關(guān)系

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

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

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

JS阻塞頁面加載

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

譬如漆魔,假設JS引擎正在進行巨量的計算坷檩,所以JS引擎很可能很久很久后才能空閑,所以導致頁面渲染加載阻塞改抡。這就牽扯到script標簽在html中的存放位置矢炼。具體可以看我另一篇文章 為什么script標簽一般放在body下面

3.js引擎是單線程的

我們知道js是單線程的。也就是說阿纤,同一個時間只能做一件事句灌。那么,為什么JavaScript不能有多個線程呢欠拾?這樣能提高效率啊涯塔。

參考阮一峰大神的文章js事件輪詢(Event Loop)

  • JavaScript的單線程,與它的用途有關(guān)清蚀。作為瀏覽器腳本語言,JavaScript的主要用途是與用戶互動爹谭,以及操作DOM枷邪。這決定了它只能是單線程,否則會帶來很復雜的同步問題诺凡。比如东揣,假定JavaScript同時有兩個線程,一個線程在某個DOM節(jié)點上添加內(nèi)容腹泌,另一個線程刪除了這個節(jié)點嘶卧,這時瀏覽器應該以哪個線程為準?
  • 所以凉袱,為了避免復雜性芥吟,從一誕生侦铜,JavaScript就是單線程,這已經(jīng)成了這門語言的核心特征钟鸵,將來也不會改變钉稍。
  • 為了利用多核CPU的計算能力,HTML5提出Web Worker標準棺耍,允許JavaScript腳本創(chuàng)建多個線程贡未,但是子線程完全受主線程控制,且不得操作DOM蒙袍。所以俊卤,這個新標準并沒有改變JavaScript單線程的本質(zhì)。

4.js事件輪詢

上面我們已經(jīng)知道JS引擎是單線程害幅,任務應該是按順序執(zhí)行的消恍,那么怎么會有同步異步之說?

  • 單線程就意味著矫限,所有任務需要排隊哺哼,前一個任務結(jié)束,才會執(zhí)行后一個任務叼风。如果前一個任務耗時很長取董,后一個任務就不得不一直等著。
  • 如果排隊是因為計算量大无宿,CPU忙不過來茵汰,倒也算了,但是很多時候CPU是閑著的孽鸡,因為IO設備(輸入輸出設備)很慢(比如Ajax操作從網(wǎng)絡讀取數(shù)據(jù))蹂午,不得不等著結(jié)果出來,再往下執(zhí)行彬碱。
  • JavaScript語言的設計者意識到豆胸,這時主線程完全可以不管IO設備,掛起處于等待中的任務巷疼,先運行排在后面的任務晚胡。等到IO設備返回了結(jié)果,再回過頭嚼沿,把掛起的任務繼續(xù)執(zhí)行下去估盘。
  • 于是,所有任務可以分成兩種骡尽,一種是同步任務(synchronous)遣妥,另一種是異步任務(asynchronous)。同步任務指的是攀细,在主線程上排隊執(zhí)行的任務箫踩,只有前一個任務執(zhí)行完畢爱态,才能執(zhí)行后一個任務;異步任務指的是班套,不進入主線程肢藐、而進入"任務隊列"(task queue)的任務,只有"任務隊列"通知主線程吱韭,某個異步任務可以執(zhí)行了吆豹,該任務才會進入主線程執(zhí)行。

理解了同步異步理盆。其實其最本質(zhì)原因就是基于js的事件輪詢機制痘煤。

  1. 所有同步任務都在主線程(即js引擎線程)上執(zhí)行,形成一個執(zhí)行棧
  2. 而異步任務均由事件觸發(fā)線程控制猿规,其有一個任務隊列衷快。只要異步任務有了運行結(jié)果,就在"任務隊列"之中放置回調(diào)事件姨俩。異步任務必須指定回調(diào)函數(shù)蘸拔,當主線程開始執(zhí)行異步任務,就是執(zhí)行對應的回調(diào)函數(shù)环葵。所以所謂"回調(diào)函數(shù)"(callback)调窍,就是那些會被主線程掛起來的代碼。
  3. 一旦"執(zhí)行棧"中的所有同步任務執(zhí)行完畢张遭,系統(tǒng)就會讀取"任務隊列"邓萨,按順序結(jié)束等待狀態(tài),進入執(zhí)行棧菊卷,開始執(zhí)行缔恳。
  4. 主線程不斷重復上面的第三步
  5. 只要主線程空了,就會去讀取"任務隊列"洁闰,這個過程會不斷重復歉甚。這就是JavaScript的運行機制。又稱為Event Loop(事件循環(huán)或者輪詢)扑眉。

5.定時器觸發(fā)線程

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

js來控制主線程铃芦,事件觸發(fā)來控制任務隊列就如主線程。

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

什么時候會用到定時器線程酵使?當使用setTimeout或setInterval時钞速,它需要定時器線程計時,計時完成后就會將特定的事件推入事件觸發(fā)線程的任務隊列中逢净。等待進入主線程執(zhí)行。

譬如:

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

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

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

console.log('begin');

//begin hello

這段代碼的效果是表示當前代碼執(zhí)行完(執(zhí)行棧清空)以后,立即執(zhí)行(0毫秒間隔)指定的回調(diào)函數(shù)茁彭。

注意:

  • 雖然代碼的本意是0毫秒后就推入事件隊列,但是html5標準中規(guī)定扶歪,規(guī)定要求setTimeout中低于4ms的時間間隔算為4ms理肺。
  • 就算不等待4ms,就算假設0毫秒就推入事件隊列善镰,也會先執(zhí)行begin(因為只有主線程可執(zhí)行棧內(nèi)空了后才會主動讀取事件隊列)妹萨。要是當前代碼耗時很長,有可能要等很久炫欺,所以并沒有辦法保證乎完,回調(diào)函數(shù)一定會在setTimeout()指定的時間執(zhí)行。同理setInterval則是每次都精確的隔一段時間推入一個事件(但是品洛,事件的實際執(zhí)行時間不一定就準確树姨,還有可能是這個事件還沒執(zhí)行完畢,下一個事件就來了)

6.總結(jié)

這里我沒有總結(jié)css渲染這塊桥状,由于內(nèi)容較多帽揪,我會另開一篇文章來講解。

寫了這么多岛宦,還是要感謝大神們的文章台丛。

js事件輪詢(Event Loop)

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末砾肺,一起剝皮案震驚了整個濱河市挽霉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌变汪,老刑警劉巖侠坎,帶你破解...
    沈念sama閱讀 216,919評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異裙盾,居然都是意外死亡实胸,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評論 3 392
  • 文/潘曉璐 我一進店門番官,熙熙樓的掌柜王于貴愁眉苦臉地迎上來庐完,“玉大人,你說我怎么就攤上這事徘熔∶徘” “怎么了?”我有些...
    開封第一講書人閱讀 163,316評論 0 353
  • 文/不壞的土叔 我叫張陵酷师,是天一觀的道長讶凉。 經(jīng)常有香客問我染乌,道長,這世上最難降的妖魔是什么懂讯? 我笑而不...
    開封第一講書人閱讀 58,294評論 1 292
  • 正文 為了忘掉前任荷憋,我火速辦了婚禮,結(jié)果婚禮上褐望,老公的妹妹穿的比我還像新娘勒庄。我一直安慰自己,他們只是感情好譬挚,可當我...
    茶點故事閱讀 67,318評論 6 390
  • 文/花漫 我一把揭開白布锅铅。 她就那樣靜靜地躺著,像睡著了一般减宣。 火紅的嫁衣襯著肌膚如雪盐须。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,245評論 1 299
  • 那天漆腌,我揣著相機與錄音贼邓,去河邊找鬼。 笑死闷尿,一個胖子當著我的面吹牛塑径,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播填具,決...
    沈念sama閱讀 40,120評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼统舀,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了劳景?” 一聲冷哼從身側(cè)響起誉简,我...
    開封第一講書人閱讀 38,964評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎盟广,沒想到半個月后闷串,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,376評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡筋量,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,592評論 2 333
  • 正文 我和宋清朗相戀三年烹吵,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片桨武。...
    茶點故事閱讀 39,764評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡肋拔,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出呀酸,到底是詐尸還是另有隱情只损,我是刑警寧澤,帶...
    沈念sama閱讀 35,460評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站跃惫,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏艾栋。R本人自食惡果不足惜爆存,卻給世界環(huán)境...
    茶點故事閱讀 41,070評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蝗砾。 院中可真熱鬧先较,春花似錦、人聲如沸悼粮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,697評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽扣猫。三九已至菜循,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間申尤,已是汗流浹背癌幕。 一陣腳步聲響...
    開封第一講書人閱讀 32,846評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留昧穿,地道東北人勺远。 一個月前我還...
    沈念sama閱讀 47,819評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像时鸵,于是被迫代替她去往敵國和親胶逢。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,665評論 2 354

推薦閱讀更多精彩內(nèi)容