瀏覽器工作原理

處理腳本和樣式表的順序

腳本

網(wǎng)絡(luò)的模型是同步的。網(wǎng)頁(yè)作者希望解析器遇到<script>標(biāo)記時(shí)立即解析并執(zhí)行腳本扳还。文檔的解析將停止,直到腳本執(zhí)行完畢橱夭。如果腳本是外部的氨距,那么解析過(guò)程會(huì)停止,直到從網(wǎng)絡(luò)同步抓取資源完成后再繼續(xù)棘劣。此模型已經(jīng)使用了多年俏让,也在HTML4 和 HTML5 規(guī)范中進(jìn)行了指定。作者也可以將腳本標(biāo)注為“defer”茬暇,這樣它就不會(huì)停止文檔解析首昔,而是等到解析結(jié)束才執(zhí)行。HTML5增加了一個(gè)選項(xiàng)糙俗,可將腳本標(biāo)記為異步勒奇,以便由其他線程解析和執(zhí)行。

預(yù)解析

WebKit和Firefox都進(jìn)行了這項(xiàng)優(yōu)化臼节。在執(zhí)行腳本時(shí)撬陵,其他線程會(huì)解析文檔的其余部分,找出并加載需要通過(guò)網(wǎng)絡(luò)加載的其他資源网缝。通過(guò)這種方式,資源可以在并行連接上加載蟋定,從而提高總體速度粉臊。請(qǐng)注意,預(yù)解析器不會(huì)修改DOM樹(shù)驶兜,而是將這項(xiàng)工作交由主解析器處理扼仲;預(yù)解析器只會(huì)解析外部資源(例如外部腳本、樣式表和圖片)的引用抄淑。

樣式表

另一方面屠凶,樣式表有著不同的模型。理論上來(lái)說(shuō)肆资,應(yīng)用樣式表不會(huì)更改 DOM 樹(shù)矗愧,因此似乎沒(méi)有必要等待樣式表并停止文檔解析。但這涉及到一個(gè)問(wèn)題郑原,就是腳本在文檔解析階段會(huì)請(qǐng)求樣式信息唉韭。如果當(dāng)時(shí)還沒(méi)有加載和解析樣式夜涕,腳本就會(huì)獲得錯(cuò)誤的回復(fù),這樣顯然會(huì)產(chǎn)生很多問(wèn)題属愤。這看上去是一個(gè)非典型案例女器,但事實(shí)上非常普遍。Firefox在樣式表加載和解析的過(guò)程中住诸,會(huì)禁止所有腳本驾胆。而對(duì)于 WebKit 而言,僅當(dāng)腳本嘗試訪問(wèn)的樣式屬性可能受尚未加載的樣式表影響時(shí)贱呐,它才會(huì)禁止該腳本俏拱。

呈現(xiàn)樹(shù)構(gòu)建

在 DOM 樹(shù)構(gòu)建的同時(shí),瀏覽器還會(huì)構(gòu)建另一個(gè)樹(shù)結(jié)構(gòu):呈現(xiàn)樹(shù)吼句。這是由可視化元素按照其顯示順序而組成的樹(shù)锅必,也是文檔的可視化表示。它的作用是讓您按照正確的順序繪制內(nèi)容惕艳。Firefox 將呈現(xiàn)樹(shù)中的元素稱為“框架”搞隐。WebKit 使用的術(shù)語(yǔ)是呈現(xiàn)器或呈現(xiàn)對(duì)象。呈現(xiàn)器知道如何布局并將自身及其子元素繪制出來(lái)远搪。

WebKits RenderObject 類是所有呈現(xiàn)器的基類劣纲,其定義如下:


每一個(gè)呈現(xiàn)器都代表了一個(gè)矩形的區(qū)域,通常對(duì)應(yīng)于相關(guān)節(jié)點(diǎn)的 CSS 框谁鳍,這一點(diǎn)在 CSS2 規(guī)范中有所描述癞季。它包含諸如寬度、高度和位置等幾何信息倘潜。

框的類型會(huì)受到與節(jié)點(diǎn)相關(guān)的“display”樣式屬性的影響绷柒。下面這段 WebKit 代碼描述了根據(jù) display 屬性的不同,針對(duì)同一個(gè) DOM 節(jié)點(diǎn)應(yīng)創(chuàng)建什么類型的呈現(xiàn)器涮因。


元素類型也是考慮因素之一废睦,例如表單控件和表格都對(duì)應(yīng)特殊的框架。在 WebKit 中养泡,如果一個(gè)元素需要?jiǎng)?chuàng)建特殊的呈現(xiàn)器嗜湃,就會(huì)替換createRenderer方法。呈現(xiàn)器所指向的樣式對(duì)象中包含了一些和幾何無(wú)關(guān)的信息澜掩。

呈現(xiàn)樹(shù)和 DOM 樹(shù)的關(guān)系

呈現(xiàn)器是和 DOM 元素相對(duì)應(yīng)的购披,但并非一一對(duì)應(yīng)。非可視化的 DOM 元素不會(huì)插入呈現(xiàn)樹(shù)中肩榕,例如“head”元素刚陡。如果元素的 display 屬性值為“none”,那么也不會(huì)顯示在呈現(xiàn)樹(shù)中(但是 visibility 屬性值為“hidden”的元素仍會(huì)顯示)。

有一些 DOM 元素對(duì)應(yīng)多個(gè)可視化對(duì)象橘荠。它們往往是具有復(fù)雜結(jié)構(gòu)的元素屿附,無(wú)法用單一的矩形來(lái)描述。例如哥童,“select”元素有 3 個(gè)呈現(xiàn)器:一個(gè)用于顯示區(qū)域挺份,一個(gè)用于下拉列表框,還有一個(gè)用于按鈕贮懈。如果由于寬度不夠匀泊,文本無(wú)法在一行中顯示而分為多行,那么新的行也會(huì)作為新的呈現(xiàn)器而添加朵你。

另一個(gè)關(guān)于多呈現(xiàn)器的例子是格式無(wú)效的 HTML各聘。根據(jù) CSS 規(guī)范,inline 元素只能包含 block 元素或 inline 元素中的一種抡医。如果出現(xiàn)了混合內(nèi)容躲因,則應(yīng)創(chuàng)建匿名的 block 呈現(xiàn)器,以包裹 inline 元素忌傻。

有一些呈現(xiàn)對(duì)象對(duì)應(yīng)于 DOM 節(jié)點(diǎn)大脉,但在樹(shù)中所在的位置與 DOM 節(jié)點(diǎn)不同。浮動(dòng)定位和絕對(duì)定位的元素就是這樣水孩,它們處于正常的流程之外镰矿,放置在樹(shù)中的其他地方,并映射到真正的框架俘种,而放在原位的是占位框架秤标。


構(gòu)建呈現(xiàn)樹(shù)的流程

在 Firefox 中,系統(tǒng)會(huì)針對(duì) DOM 更新注冊(cè)展示層宙刘,作為偵聽(tīng)器苍姜。展示層將框架創(chuàng)建工作委托給FrameConstructor,由該構(gòu)造器解析樣式(請(qǐng)參閱樣式計(jì)算)并創(chuàng)建框架荐类。

在 WebKit 中怖现,解析樣式和創(chuàng)建呈現(xiàn)器的過(guò)程稱為“附加”。每個(gè) DOM 節(jié)點(diǎn)都有一個(gè)“attach”方法玉罐。附加是同步進(jìn)行的,將節(jié)點(diǎn)插入 DOM 樹(shù)需要調(diào)用新的節(jié)點(diǎn)“attach”方法潘拨。

處理 html 和 body 標(biāo)記就會(huì)構(gòu)建呈現(xiàn)樹(shù)根節(jié)點(diǎn)吊输。這個(gè)根節(jié)點(diǎn)呈現(xiàn)對(duì)象對(duì)應(yīng)于 CSS 規(guī)范中所說(shuō)的容器 block,這是最上層的 block铁追,包含了其他所有 block季蚂。它的尺寸就是視口,即瀏覽器窗口顯示區(qū)域的尺寸。Firefox 稱之為ViewPortFrame扭屁,而 WebKit 稱之為RenderView算谈。這就是文檔所指向的呈現(xiàn)對(duì)象。呈現(xiàn)樹(shù)的其余部分以 DOM 樹(shù)節(jié)點(diǎn)插入的形式來(lái)構(gòu)建料滥。

共享樣式數(shù)據(jù)

WebKit 節(jié)點(diǎn)會(huì)引用樣式對(duì)象 (RenderStyle)然眼。這些對(duì)象在某些情況下可以由不同節(jié)點(diǎn)共享。這些節(jié)點(diǎn)是同級(jí)關(guān)系葵腹,并且:

1.這些元素必須處于相同的鼠標(biāo)狀態(tài)(例如高每,不允許其中一個(gè)是“:hover”狀態(tài),而另一個(gè)不是)

2.任何元素都沒(méi)有 ID

3.標(biāo)記名稱應(yīng)匹配

4.類屬性應(yīng)匹配

5.映射屬性的集合必須是完全相同的

6.鏈接狀態(tài)必須匹配

7.焦點(diǎn)狀態(tài)必須匹配

8.任何元素都不應(yīng)受屬性選擇器的影響践宴,這里所說(shuō)的“影響”是指在選擇器中的任何位置有任何使用了屬性選擇器的選擇器匹配

9.元素中不能有任何 inline 樣式屬性

10.不能使用任何同級(jí)選擇器鲸匿。WebCore 在遇到任何同級(jí)選擇器時(shí),只會(huì)引發(fā)一個(gè)全局開(kāi)關(guān)阻肩,并停用整個(gè)文檔的樣式共享(如果存在)带欢。這包括 + 選擇器以及 :first-child 和 :last-child 等選擇器。

布局

呈現(xiàn)器在創(chuàng)建完成并添加到呈現(xiàn)樹(shù)時(shí)烤惊,并不包含位置和大小信息乔煞。計(jì)算這些值的過(guò)程稱為布局或重排。

HTML 采用基于流的布局模型撕氧,這意味著大多數(shù)情況下只要一次遍歷就能計(jì)算出幾何信息瘤缩。處于流中靠后位置元素通常不會(huì)影響靠前位置元素的幾何特征,因此布局可以按從左至右伦泥、從上至下的順序遍歷文檔剥啤。但是也有例外情況,比如 HTML 表格的計(jì)算就需要不止一次的遍歷 (3.5)不脯。

坐標(biāo)系是相對(duì)于根框架而建立的府怯,使用的是上坐標(biāo)和左坐標(biāo)。

布局是一個(gè)遞歸的過(guò)程防楷。它從根呈現(xiàn)器(對(duì)應(yīng)于 HTML 文檔的元素)開(kāi)始牺丙,然后遞歸遍歷部分或所有的框架層次結(jié)構(gòu),為每一個(gè)需要計(jì)算的呈現(xiàn)器計(jì)算幾何信息复局。

根呈現(xiàn)器的位置左邊是 0,0冲簿,其尺寸為視口(也就是瀏覽器窗口的可見(jiàn)區(qū)域)。

所有的呈現(xiàn)器都有一個(gè)“l(fā)ayout”或者“reflow”方法亿昏,每一個(gè)呈現(xiàn)器都會(huì)調(diào)用其需要進(jìn)行布局的子代的 layout 方法峦剔。

Dirty 位系統(tǒng)

為避免對(duì)所有細(xì)小更改都進(jìn)行整體布局,瀏覽器采用了一種“dirty 位”系統(tǒng)角钩。如果某個(gè)呈現(xiàn)器發(fā)生了更改吝沫,或者將自身及其子代標(biāo)注為“dirty”呻澜,則需要進(jìn)行布局。

有兩種標(biāo)記:“dirty”和“children are dirty”惨险「遥“children are dirty”表示盡管呈現(xiàn)器自身沒(méi)有變化,但它至少有一個(gè)子代需要布局辫愉。

全局布局和增量布局

全局布局是指觸發(fā)了整個(gè)呈現(xiàn)樹(shù)范圍的布局栅受,觸發(fā)原因可能包括:

1.影響所有呈現(xiàn)器的全局樣式更改,例如字體大小更改一屋。

2.屏幕大小調(diào)整窘疮。

布局可以采用增量方式,也就是只對(duì) dirty 呈現(xiàn)器進(jìn)行布局(這樣可能存在需要進(jìn)行額外布局的弊端)冀墨。

當(dāng)呈現(xiàn)器為 dirty 時(shí)闸衫,會(huì)異步觸發(fā)增量布局。例如诽嘉,當(dāng)來(lái)自網(wǎng)絡(luò)的額外內(nèi)容添加到 DOM 樹(shù)之后蔚出,新的呈現(xiàn)器附加到了呈現(xiàn)樹(shù)中。

異步布局和同步布局

增量布局是異步執(zhí)行的虫腋。Firefox 將增量布局的“reflow 命令”加入隊(duì)列骄酗,而調(diào)度程序會(huì)觸發(fā)這些命令的批量執(zhí)行。WebKit 也有用于執(zhí)行增量布局的計(jì)時(shí)器:對(duì)呈現(xiàn)樹(shù)進(jìn)行遍歷悦冀,并對(duì) dirty 呈現(xiàn)器進(jìn)行布局趋翻。

請(qǐng)求樣式信息(例如“offsetHeight”)的腳本可同步觸發(fā)增量布局。

全局布局往往是同步觸發(fā)的盒蟆。

有時(shí)踏烙,當(dāng)初始布局完成之后,如果一些屬性(如滾動(dòng)位置)發(fā)生變化历等,布局就會(huì)作為回調(diào)而觸發(fā)讨惩。

優(yōu)化

如果布局是由“大小調(diào)整”或呈現(xiàn)器的位置(而非大小)改變而觸發(fā)的寒屯,那么可以從緩存中獲取呈現(xiàn)器的大小荐捻,而無(wú)需重新計(jì)算。

在某些情況下寡夹,只有一個(gè)子樹(shù)進(jìn)行了修改处面,因此無(wú)需從根節(jié)點(diǎn)開(kāi)始布局。這適用于在本地進(jìn)行更改而不影響周圍元素的情況菩掏,例如在文本字段中插入文本(否則每次鍵盤(pán)輸入都將觸發(fā)從根節(jié)點(diǎn)開(kāi)始的布局)鸳君。

布局處理

布局通常具有以下模式:

1.父呈現(xiàn)器確定自己的寬度。

2.父呈現(xiàn)器依次處理子呈現(xiàn)器患蹂,并且:

? ? 1.放置子呈現(xiàn)器(設(shè)置 x,y 坐標(biāo))或颊。

? ? 2.如果有必要,調(diào)用子呈現(xiàn)器的布局(如果子呈現(xiàn)器是 dirty 的传于,或者這是全局布局囱挑,或出于其他某些原因),這會(huì)計(jì)算子呈現(xiàn)器的高度沼溜。

3.父呈現(xiàn)器根據(jù)子呈現(xiàn)器的累加高度以及邊距和補(bǔ)白的高度來(lái)設(shè)置自身高度平挑,此值也可供父呈現(xiàn)器的父呈現(xiàn)器使用。

4.將其 dirty 位設(shè)置為 false系草。

Firefox 使用“state”對(duì)象 (nsHTMLReflowState) 作為布局的參數(shù)(稱為“reflow”)通熄,這其中包括了父呈現(xiàn)器的寬度。

Firefox 布局的輸出為“metrics”對(duì)象 (nsHTMLReflowMetrics)找都,其包含計(jì)算得出的呈現(xiàn)器高度

標(biāo)記時(shí)立即解析并執(zhí)行腳本唇辨。文檔的解析將停止,直到腳本執(zhí)行完畢能耻。如果腳本是外部的赏枚,那么解析過(guò)程會(huì)停止,直到從網(wǎng)絡(luò)同步抓取資源完成后再繼續(xù)晓猛。此模型已經(jīng)使用了多年饿幅,也在 HTML4 和 HTML5 規(guī)范中進(jìn)行了指定。作者也可以將腳本標(biāo)注為“defer”戒职,這樣它就不會(huì)停止文檔解析栗恩,而是等到解析結(jié)束才執(zhí)行。HTML5 增加了一個(gè)選項(xiàng)洪燥,可將腳本標(biāo)記為異步磕秤,以便由其他線程解析和執(zhí)行。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蚓曼,一起剝皮案震驚了整個(gè)濱河市亲澡,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌纫版,老刑警劉巖床绪,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異其弊,居然都是意外死亡癞己,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)梭伐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)痹雅,“玉大人,你說(shuō)我怎么就攤上這事糊识〖ㄉ纾” “怎么了摔蓝?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)愉耙。 經(jīng)常有香客問(wèn)我贮尉,道長(zhǎng),這世上最難降的妖魔是什么朴沿? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任猜谚,我火速辦了婚禮,結(jié)果婚禮上赌渣,老公的妹妹穿的比我還像新娘魏铅。我一直安慰自己,他們只是感情好坚芜,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布览芳。 她就那樣靜靜地躺著,像睡著了一般货岭。 火紅的嫁衣襯著肌膚如雪路操。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,111評(píng)論 1 285
  • 那天千贯,我揣著相機(jī)與錄音屯仗,去河邊找鬼。 笑死搔谴,一個(gè)胖子當(dāng)著我的面吹牛魁袜,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播敦第,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼峰弹,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了芜果?” 一聲冷哼從身側(cè)響起鞠呈,我...
    開(kāi)封第一講書(shū)人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎右钾,沒(méi)想到半個(gè)月后蚁吝,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡舀射,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年窘茁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片脆烟。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡山林,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出邢羔,到底是詐尸還是另有隱情驼抹,我是刑警寧澤桑孩,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站砂蔽,受9級(jí)特大地震影響洼怔,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜左驾,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望极谊。 院中可真熱鬧诡右,春花似錦、人聲如沸轻猖。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)咙边。三九已至猜煮,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間败许,已是汗流浹背王带。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留市殷,地道東北人愕撰。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像醋寝,于是被迫代替她去往敵國(guó)和親搞挣。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

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