瀏覽器解析html

一、進程和線程

1.應用程序是有一個或多個模塊組成的抹锄,以現(xiàn)在的谷歌瀏覽器舉例逆瑞,他有一個瀏覽器主進程、一個GPU進程祈远、一個網(wǎng)絡進程呆万、多個渲染進程和多個插件進程商源。

2.進程是由一個或者多個線程組成的车份,線程是進程的基本單位。

3.進程之間互相獨立牡彻,有自己的資源扫沼,比如CPU的時間片,占用的內存庄吼。

4.一個進程下的線程(工人)共享進程(工廠)的資源缎除,包括代碼段、數(shù)據(jù)段总寻、內存等器罐。

5.線程之間協(xié)作在進程中完成任務。

6.進程是CPU資源分配的最小單位渐行,是可以擁有資源和獨立運行的最小單位轰坊。

7.線程是CPU調度的最小單位铸董,因為進程可以有一個或者多個線程。

tips:瀏覽器打開多個便簽頁肴沫,都會增加進程數(shù)量粟害,比如我用IE瀏覽器打開百度、京東颤芬、淘寶悲幅。

二、瀏覽器進程與線程

瀏覽器是多進程的站蝠,其中包含了:

? ? ?1)Browser進程------主進程只有一個汰具,負責協(xié)調、控制菱魔。比如創(chuàng)建Tab頁面郁副,或者銷毀頁面、下載網(wǎng)絡資源等豌习。

? ? ?2)GPU進程------最多一個存谎,用于繪畫3D。

? ? ?3)第三方插件進程------每種類型的插件對應一個進程肥隆,使用一個就開辟一個進程既荚。

? ? ?4)網(wǎng)絡進程------網(wǎng)絡請求,返回數(shù)據(jù)

? ? ?5)瀏覽器渲染進程------默認每個Tab頁面一個進程栋艳,互不影響恰聘。

? ? ?這里面的進程很好理解,瀏覽器本身吸占,第三方插件擴容晴叨,瀏覽器渲染,GPU矾屯。其中兼蕊,瀏覽器渲染JS就是通過瀏覽器渲染進程進行的。

? ? ?瀏覽器渲染引擎是多線程的件蚕,其中包括以下線程:

? ? ?1)GUI渲染線程? ?--->? 界面渲染

????????GUI渲染線程主要負責渲染頁面的孙技,解析HTML、CSS排作,構建成一個DOM樹和render樹牵啦;當界面需要重繪或者重排引發(fā)回流時,這個線程會? ? ? ?????執(zhí)行妄痪。注意哈雏,GUI渲染線程和JS引擎執(zhí)行是互斥的,當js引擎執(zhí)行時,GUI線程會被掛起裳瘪,保存到一個任務隊列中履因,等到JS引擎線程空閑時? ? ? ?????候才會出隊被立即執(zhí)行。如果不互斥盹愚,你一邊用戶操作一遍渲染界面栅迄,會導致渲染不準確等,這就決定了JS是單線程的了皆怕。? ??????????

? ? ?2)JS引擎線程? ? ?--->? ?JS處理

? ??????負責處理js腳本毅舆,解析腳本運行代碼。但是js引擎會一直等待著任務隊列的到來愈腾,然后加以處理憋活。同樣,GUI渲染線程和JS引擎執(zhí)行是互斥? ?????????虱黄,如果js執(zhí)行的時候太長悦即,就會導致頁面渲染不連貫,也就是阻塞頁面橱乱,導致了頁面渲染加載被阻塞了辜梳,這就是為什么常常不把script標簽 ????????放在頭部而放在body底部下的原因。

? ? ?3)事件觸發(fā)線程? --->? ?事件處理

? ? ?4)定時器線程? ? ? --->? ?定時器處理

? ? ?5)http異步請求線程? ? ?----> 異步請求處理


? ? ?一般我們前端所學的就是對以上線程的操作和處理泳叠,管理好以上線程對我們前端技術能夠有很大的提升作瞄。

browser主進程和其它進程的通信


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

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

渲染線程接收請求契耿,加載網(wǎng)頁并渲染網(wǎng)頁,這其中可能需要Browser主進程獲取資源和需要GPU進程來幫助渲染螃征,這期間都是主進程調度協(xié)助進程完成的搪桂。

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

最后Render進程將結果傳遞給Browser進程

Browser主進程接收到每個協(xié)作進程處理好的結果后,將結果繪制出來

三会傲、梳理瀏覽器內核線程之間的關系

渲染進程锅棕,即瀏覽器內核,才是我們前端關注的重點淌山,再次強調一下。然后我們必須知道一下幾點顾瞻。

1.GUI線程和JS引擎線程是互斥的

2.因為第1點泼疑,如果JS引擎執(zhí)行時間很久,就會引發(fā)頁面阻塞

3.HTML5中支持了Web Worker荷荤,以解決頁面阻塞退渗,但是Web Worker是JS引擎子線程移稳,受JS引擎控制,JS單線程依舊不會改變

四会油、瀏覽器渲染流程

這個過程也很復雜个粱,可以參考我之前的計算機網(wǎng)絡(前端版)的問題,過多的細節(jié)不在這里描述翻翩。這里只做簡單的描述

1.瀏覽器輸入URL都许,瀏覽器主線程接管,開一個下載線程嫂冻,已進行http請求胶征。(忽略DNS等等)

2.拿到響應內容,將內容通過RendererHost接口轉交給Renderer渲染進程

3.瀏覽器開始渲染(可能會協(xié)調GPU等線程協(xié)作完成)

渲染進程(內核)拿到內容后桨仿,分以下幾步開始渲染:

1.解析HTML建立dom樹

2.解析CSS構建render樹睛低,其實就是講css解析成樹的數(shù)據(jù)結構,然后結合dom樹形成render樹服傍。

3.布局render樹(Layout/reflow)钱雷,復雜計算元素的大小、位置等信息

4.開始繪制render樹(paint)吹零,繪制頁面像素信息

5.瀏覽器會將繪制信息發(fā)送給GPU急波,GPU會將合成(composite),顯示在屏幕上瘪校。


注意細節(jié)

1.DOMContentLoaded 事件觸發(fā)時愉耙,僅當DOM加載完成,不包括樣式表红氯,圖片躺彬。有async的腳本也不一定完成。

2.當 onload 事件觸發(fā)時麻惶,頁面上所有的DOM馍刮,樣式表,腳本窃蹋,圖片都已經(jīng)加載完成了卡啰。頁面渲染完畢。

3.css加載不會阻塞DOM樹解析(異步加載時DOM照常構建)警没;但會阻塞render樹渲染(渲染時需等css加載完畢匈辱,因為render樹需要css信息)

4.渲染步驟中就提到了composite的概念,可以簡單的理解為杀迹,瀏覽器渲染圖層一般包括兩大類亡脸,就是普通圖層復合圖層。

5.文檔就可以當做一個默認的復合圖層,其次absolute這樣的脫離文檔流也依然屬于復合圖層浅碾。硬件加速什么的這里就不展開描述了大州。

五、JavaScript引擎

avaScript引擎從頭到尾負責整個JavaScript程序的編譯和執(zhí)行過程垂谢。js的引擎有很多種厦画,而最為大家熟知的無疑是V8引擎,他用于Chrome瀏覽器和Node中滥朱。


V8引擎由兩個主要部件組成:

emory Heap(內存堆)?—?內存分配地址的地方

Call Stack(調用堆棧) — 代碼執(zhí)行的地方

js引擎執(zhí)行過程

全面分析js引擎的執(zhí)行過程根暑,主要分為三個階段:

1. 語法分析

2. 預編譯階段

3. 執(zhí)行階段

不同的運行環(huán)境執(zhí)行都會進入到代碼預編譯和執(zhí)行兩個階段,語法分析則在代碼塊加載完畢時統(tǒng)一檢查語法焚虱。

(一)語法分析

分析該js腳本代碼塊的語法是否正確购裙,如果出現(xiàn)不正確,則向外拋出一個語法錯誤(SyntaxError)鹃栽,停止該js代碼塊的執(zhí)行躏率,然后繼續(xù)查找并加載下一個代碼塊;如果語法正確民鼓,則進入預編譯階段

(二)預編譯階段


js代碼塊通過語法分析階段之后薇芝,語法都正確的下回進入預編譯階段。

在分析預編譯階段之前丰嘉,我們先來了解一下js的運行環(huán)境夯到,運行環(huán)境主要由三種:

1、全局環(huán)境(js代碼加載完畢后饮亏,進入到預編譯也就是進入到全局環(huán)境)

2耍贾、函數(shù)環(huán)境(函數(shù)調用的時候,進入到該函數(shù)環(huán)境路幸,不同的函數(shù)荐开,函數(shù)環(huán)境不同)

3、eval環(huán)境(不建議使用简肴,存在安全晃听、性能問題)

每進入到一個不同的運行環(huán)境都會創(chuàng)建一個相應的執(zhí)行上下文(execution context)「下文會介紹」,那么在一段js程序中一般都會創(chuàng)建多個執(zhí)行上下文砰识,js引擎會以棧的數(shù)據(jù)結構對這些執(zhí)行進行處理能扒,形成函數(shù)調用棧(call stack),棧底永遠是全局執(zhí)行上下文(global execution context)辫狼,棧頂則永遠時當前的執(zhí)行上下文初斑。

我們聲明的函數(shù)與變量被儲存在『內存堆』中,而當我們要執(zhí)行的時候予借,就必須借助于『調用椩狡剑』來解決問題频蛔。函數(shù)調用棧就是使用棧存取的方式進行管理運行環(huán)境灵迫,特點是先進后出秦叛,后進后出



1、首先進入到全局環(huán)境瀑粥,創(chuàng)建全局執(zhí)行上下文(global Execution Context )挣跋,推入到stack中;

2狞换、調用bar函數(shù)避咆,進入bar函數(shù)運行環(huán)境,創(chuàng)建bar函數(shù)執(zhí)行上下文(bar Execution Context)修噪,推入stack棧中查库;

3、在bar函數(shù)內部調用foo函數(shù)黄琼,則再進入到foo函數(shù)運行環(huán)境中樊销,創(chuàng)建foo函數(shù)執(zhí)行上下文(foo Execution Context),如上圖脏款,由于foo函數(shù)內部沒有再調用其他函數(shù)围苫,那么則開始出棧;

5撤师、foo函數(shù)執(zhí)行完畢之后剂府,棧頂foo函數(shù)執(zhí)行上下文(foo Execution Context)首先出棧;

6剃盾、bar函數(shù)執(zhí)行完畢腺占,bar函數(shù)執(zhí)行上下文(bar Execution Context)出棧;

7痒谴、全局上下文(global Execution Cntext)在瀏覽器或者該標簽關閉的時候出棧衰伯。

執(zhí)行上下文分為兩個階段:

創(chuàng)建階段

執(zhí)行階段

創(chuàng)建階段

創(chuàng)建執(zhí)行上下文的過程中,主要是做了下面三件事闰歪,如圖所示:

1嚎研、確定 this 的值,也被稱為 This Binding库倘。

2临扮、LexicalEnvironment(詞法環(huán)境) 組件被創(chuàng)建。

3教翩、VariableEnvironment(變量環(huán)境) 組件被創(chuàng)建杆勇。

This Binding

全局執(zhí)行上下文中,this的值指向全局對象饱亿,在瀏覽器中this的值指向window對象蚜退,而在nodejs中指向這個文件的module對象闰靴。

函數(shù)執(zhí)行上下文中,this的值取決于函數(shù)的調用方式钻注。具體有:默認綁定蚂且、隱式綁定、顯式綁定(硬綁定)幅恋、new綁定杏死、箭頭函數(shù),

詞法環(huán)境有兩個組成部分

1捆交、環(huán)境記錄:存儲變量和函數(shù)聲明的實際位置

????環(huán)境記錄有三種類型淑翼,分別是聲明式環(huán)境記錄(Declarative Environment Record)對象式環(huán)境記錄(Object EnvironmentRecord)品追、????全局環(huán)境記錄(Global Environment Record)? ??

2玄括、對外部環(huán)境的引用:可以訪問其外部詞法環(huán)境


在初始化環(huán)境記錄遇到函數(shù)聲明時會創(chuàng)建一個內部函數(shù)對象,這個函數(shù)對象有一個scope屬性指向函數(shù)聲明所在的環(huán)境,如在該代碼示例中,掃描到bar()函數(shù)聲明時會在foo environment中創(chuàng)建一個內部函數(shù)對象,其scope屬性指向bar()函數(shù)聲明所在的foo environment,重要的一點是:當開始執(zhí)行bar()函數(shù)前初始化bar()函數(shù)的環(huán)境時,就把bar()函數(shù)的scope屬性指向的foo environment 賦值給bar環(huán)境的out reference作為其外部引用

外部詞法環(huán)境的引用將一個詞法環(huán)境和其外部詞法環(huán)境鏈接起來,外部詞法環(huán)境又擁有對其自身的外部詞法環(huán)境的引用肉瓦。這樣就形成一個鏈式結構遭京,這里我們稱其為環(huán)境鏈(即ES6之前的作用域鏈),全局環(huán)境是這條鏈的頂端风宁。

環(huán)境鏈的存在是為了標識符的解析洁墙,通俗的說就是查找變量。首先在當前環(huán)境查找變量戒财,找不到就去外部環(huán)境找热监,還找不到就去外部環(huán)境的外部環(huán)境找,以此類推饮寞,直到找到孝扛,或者到環(huán)境鏈頂端(全局環(huán)境)還未找到則拋出ReferenceError。

詞法環(huán)境有兩種類型

1幽崩、全局環(huán)境:是一個沒有外部環(huán)境的詞法環(huán)境苦始,其外部環(huán)境引用為null。擁有一個全局對象(window 對象)及其關聯(lián)的方法和屬性(例如數(shù)組方法)以及任何用戶自定義的全局變量慌申,this的值指向這個全局對象陌选。

2、函數(shù)環(huán)境:用戶在函數(shù)中定義的變量被存儲在環(huán)境記錄中蹄溉,包含了arguments對象咨油。對外部環(huán)境的引用可以是全局環(huán)境,也可以是包含內部函數(shù)的外部函數(shù)環(huán)境柒爵。

直接看偽代碼可能更加直觀


變量環(huán)境

變量環(huán)境也是一個詞法環(huán)境役电,因此它具有上面定義的詞法環(huán)境的所有屬性。

在 ES6 中棉胀,詞法環(huán)境和變量環(huán)境的區(qū)別在于前者用于存儲函數(shù)聲明和變量(let和const)綁定法瑟,而后者僅用于存儲變量(var)綁定冀膝。

使用例子進行介紹



變量提升的原因:在創(chuàng)建階段,函數(shù)聲明存儲在環(huán)境中霎挟,而變量會被設置為undefined(在var的情況下)或保持未初始化(在let和const的情況下)窝剖。所以這就是為什么可以在聲明之前訪問var定義的變量(盡管是undefined),但如果在聲明之前訪問let和const定義的變量就會提示引用錯誤的原因氓扛。這就是所謂的變量提升枯芬。


詞法分析:

第一步论笔,分析函數(shù)參數(shù):

形式參數(shù):AO.age = undefined

實參:AO.age = 18

第二步采郎,分析局部變量:

第3行代碼有var age,但此時第一步中已有AO.age = 18,故不做任何改變

即AO.age = 18

第三步,分析函數(shù)聲明:

第5行代碼有函數(shù)age狂魔,則將function age(){}付給AO.age,即AO.age = function age() {}

所以蒜埋,執(zhí)行代碼時:

  第2行代碼運行時拿到的age是詞法分析后的AO.age,結果是:function age() {};

  第3行代碼:25賦給age最楷,此時age=25整份;

  第4行代碼運行時age已被賦值為25,結果25籽孙;

第5,6行代碼是一個函數(shù)表達式烈评,所以不會做任何操作;

  第7行代碼運行時age仍然是25犯建,結果也是25讲冠。看看瀏覽器執(zhí)行的結果适瓦,bingo~~


六竿开、瀏覽器渲染流程

?在JS引擎線程中,可以分為同步和異步任務玻熙,其中:

1)同步任務全部通過主線程執(zhí)行否彩,形成?執(zhí)行棧

2)異步任務通過事件觸發(fā)線程或者定時器線程處理,形成?任務隊列

3)當執(zhí)行棧中的任務全部處理完成嗦随,主線程為空閑的時候列荔,會從任務隊列中提取任務到執(zhí)行棧中執(zhí)行。


在JS中又兩種任務枚尼,同步任務和異步任務贴浙,又有兩種任務類型?macrotask?和?microtask:

? ? ?1)macr0task: 宏任務,如主代碼塊任務姑原,setTimeout悬而,setInterval等,是從事件隊列中取一個事件回調放到執(zhí)行棧中執(zhí)行锭汛。

? ? ?2)microtask:微任務笨奠,如Promise袭蝗,Process.nextTick(),是執(zhí)行棧執(zhí)行完后立即執(zhí)行的任務。



最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末般婆,一起剝皮案震驚了整個濱河市到腥,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蔚袍,老刑警劉巖乡范,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異啤咽,居然都是意外死亡晋辆,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進店門宇整,熙熙樓的掌柜王于貴愁眉苦臉地迎上來瓶佳,“玉大人,你說我怎么就攤上這事鳞青“运牵” “怎么了?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵臂拓,是天一觀的道長厚脉。 經(jīng)常有香客問我,道長胶惰,這世上最難降的妖魔是什么傻工? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮童番,結果婚禮上精钮,老公的妹妹穿的比我還像新娘。我一直安慰自己剃斧,他們只是感情好轨香,可當我...
    茶點故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著幼东,像睡著了一般臂容。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上根蟹,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天脓杉,我揣著相機與錄音,去河邊找鬼简逮。 笑死球散,一個胖子當著我的面吹牛,可吹牛的內容都是我干的散庶。 我是一名探鬼主播蕉堰,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼凌净,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了屋讶?” 一聲冷哼從身側響起冰寻,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎皿渗,沒想到半個月后斩芭,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡乐疆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年划乖,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片诀拭。...
    茶點故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡迁筛,死狀恐怖,靈堂內的尸體忽然破棺而出耕挨,到底是詐尸還是另有隱情,我是刑警寧澤尉桩,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布筒占,位于F島的核電站,受9級特大地震影響蜘犁,放射性物質發(fā)生泄漏翰苫。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一这橙、第九天 我趴在偏房一處隱蔽的房頂上張望奏窑。 院中可真熱鬧,春花似錦屈扎、人聲如沸埃唯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽墨叛。三九已至,卻和暖如春模蜡,著一層夾襖步出監(jiān)牢的瞬間漠趁,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工忍疾, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留闯传,地道東北人。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓卤妒,卻偏偏與公主長得像甥绿,于是被迫代替她去往敵國和親叠必。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,092評論 2 355

推薦閱讀更多精彩內容