您好,登錄后才能下訂單哦!
本篇內(nèi)容介紹了“web前端頁(yè)面渲染機(jī)制是什么”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
瀏覽器
在介紹瀏覽器工作流程之前,先了解一下主流瀏覽器的基礎(chǔ)結(jié)構(gòu),本文所介紹的瀏覽器主要為開(kāi)源的Chrome,F(xiàn)ireFox及部分開(kāi)源的Safari,這也是目前市場(chǎng)占比***的幾大瀏覽器,以本人博客網(wǎng)站為例,可以大致看出各瀏覽器使用比例:
瀏覽器基礎(chǔ)結(jié)構(gòu)
瀏覽器基礎(chǔ)結(jié)構(gòu)主要包括如下7部分:
1.用戶(hù)界面(User Interface):用戶(hù)所看到及與之交互的功能組件,如地址欄,返回,前進(jìn)按鈕等;
2.瀏覽器引擎(Browser engine):負(fù)責(zé)控制和管理下一級(jí)的渲染引擎;
3.渲染引擎(Rendering engine):負(fù)責(zé)解析用戶(hù)請(qǐng)求的內(nèi)容(如HTML或XML,渲染引擎會(huì)解析HTML或XML,以及相關(guān)CSS,然后返回解析后的內(nèi)容);
4.網(wǎng)絡(luò)(Networking):負(fù)責(zé)處理網(wǎng)絡(luò)相關(guān)的事務(wù),如HTTP請(qǐng)求等;
5.UI后端(UI backend):負(fù)責(zé)繪制提示框等瀏覽器組件,其底層使用的是操作系統(tǒng)的用戶(hù)接口;
6.JavaScript解釋器(JavaScript interpreter):負(fù)責(zé)解析和執(zhí)行JavaScript代碼;
7.數(shù)據(jù)存儲(chǔ)(Data storage):負(fù)責(zé)持久存儲(chǔ)諸如cookie和緩存等應(yīng)用數(shù)據(jù)。
瀏覽器內(nèi)核
各大主要瀏覽器使用內(nèi)核也是有差別的,大致可以分為以下幾類(lèi):
Trident內(nèi)核: IE
Webkit內(nèi)核:Chrome,Safari
Gecko內(nèi)核:FireFox
網(wǎng)絡(luò)
當(dāng)用戶(hù)訪(fǎng)問(wèn)頁(yè)面時(shí),瀏覽器需要獲取用戶(hù)請(qǐng)求內(nèi)容,這個(gè)過(guò)程主要涉及瀏覽器網(wǎng)絡(luò)模塊:
1.用戶(hù)在地址欄輸入域名,如baidu.com,DNS(Domain Name System,域名解析系統(tǒng))服務(wù)器根據(jù)輸入的域名查找對(duì)應(yīng)IP,然后向該IP地址發(fā)起請(qǐng)求;
DNS
2.瀏覽器獲得并解析服務(wù)器的返回內(nèi)容(HTTP response);
3.瀏覽器加載HTML文件及文件內(nèi)包含的外部引用文件及圖片,多媒體等資源。
DNS預(yù)解析(DNS prefetch)
瀏覽器DNS解析大多時(shí)候較快,且會(huì)緩存常用域名的解析值,但是如果網(wǎng)站涉及多域名,在對(duì)每一個(gè)域名訪(fǎng)問(wèn)時(shí)都需要先解析出IP地址,而我們希望在跳轉(zhuǎn)或者請(qǐng)求其他域名資源時(shí)盡量快,則可以開(kāi)啟域名預(yù)解析,瀏覽器會(huì)在空閑時(shí)提前解析聲明需要預(yù)解析的域名,如:
多進(jìn)程
我們通常說(shuō)JavaScript執(zhí)行是單進(jìn)程的,但是瀏覽器網(wǎng)絡(luò)部分通常是有幾個(gè)平行進(jìn)程同時(shí)開(kāi)啟,但是也會(huì)有
限制,一般為2-6個(gè)。
渲染引擎及關(guān)鍵渲染路徑(Critical Rendering Path)
渲染引擎所做的事是將請(qǐng)求內(nèi)容展現(xiàn)給我們,默認(rèn)支持HTML,XML和圖片類(lèi)型,對(duì)于其他諸如PDF等類(lèi)型的內(nèi)容則需要安裝相應(yīng)插件,但瀏覽器的展示工作流程基本是一樣的。
通過(guò)網(wǎng)絡(luò)模塊加載到HTML文件后渲染引擎渲染流程如下,這也通常被稱(chēng)作關(guān)鍵渲染路徑(Critical Rendering Path):
1.構(gòu)建DOM樹(shù)(DOM tree):從上到下解析HTML文檔生成DOM節(jié)點(diǎn)樹(shù)(DOM tree),也叫內(nèi)容樹(shù)(content tree);
2.構(gòu)建CSSOM(CSS Object Model)樹(shù):加載解析樣式生成CSSOM樹(shù);
3.執(zhí)行JavaScript:加載并執(zhí)行JavaScript代碼(包括內(nèi)聯(lián)代碼或外聯(lián)JavaScript文件);
4.構(gòu)建渲染樹(shù)(render tree):根據(jù)DOM樹(shù)和CSSOM樹(shù),生成渲染樹(shù)(render tree);渲染樹(shù):按順序展示在屏幕上的一系列矩形,這些矩形帶有字體,顏色和尺寸等視覺(jué)屬性。
5.布局(layout):根據(jù)渲染樹(shù)將節(jié)點(diǎn)樹(shù)的每一個(gè)節(jié)點(diǎn)布局在屏幕上的正確位置;
6.繪制(painting):遍歷渲染樹(shù)繪制所有節(jié)點(diǎn),為每一個(gè)節(jié)點(diǎn)適用對(duì)應(yīng)的樣式,這一過(guò)程是通過(guò)UI后端模塊完成;
為了更友好的用戶(hù)體驗(yàn),瀏覽器會(huì)盡可能快的展現(xiàn)內(nèi)容,而不會(huì)等到文檔所有內(nèi)容到達(dá)才開(kāi)始解析和構(gòu)建/布局渲染樹(shù),而是每次處理一部分,并展現(xiàn)在屏幕上,這也是為什么我們經(jīng)常可以看到頁(yè)面加載的時(shí)候內(nèi)容是從上到下一點(diǎn)一點(diǎn)展現(xiàn)的。
流程圖
Webkit渲染引擎流程如下圖:
Gecko渲染引擎流程如下圖:
如上圖,Webkit瀏覽器和Gecko瀏覽器渲染流程大致相同,不同的是:
1.Webkit瀏覽器中的渲染樹(shù)(render tree),在Gecko瀏覽器中對(duì)應(yīng)的則是框架樹(shù)(frame tree),渲染對(duì)象(render object)對(duì)應(yīng)的是框架(frame);
2.Webkit中的布局(Layout)過(guò)程,在Gecko中稱(chēng)為回流(Reflow),本質(zhì)是一樣的,后文會(huì)解釋回流的另一層含義–重新布局;
3.Gecko中HTML和DOM樹(shù)中間多了一層內(nèi)容池(Content sink),可以理解成生成DOM元素的工廠。
單進(jìn)程
不同于網(wǎng)絡(luò)部分的多進(jìn)程渲染引擎是單線(xiàn)程工作的,意味著渲染流程是一步一步漸進(jìn)完成的。
解析文檔(parser HTML)
在詳細(xì)介紹瀏覽器渲染文檔之前,先應(yīng)該理解瀏覽器如何解析文檔:解析文檔的順序,對(duì)于CSS和JavaScript如何處理等。
解析順序
瀏覽器按從上到下的順序掃描解析文檔;
解析樣式和腳本
腳本或許是由于通常會(huì)在JavaScript腳本中改變文檔DOM結(jié)構(gòu),于是瀏覽器以同步方式解析,加載和執(zhí)行腳本,瀏覽器在解析文檔時(shí),當(dāng)解析到標(biāo)簽時(shí),會(huì)解析其中的腳本(對(duì)于外鏈的JavaScript文件,需要先加載該文件內(nèi)容,再進(jìn)行解析),然后立即執(zhí)行,這整個(gè)過(guò)程都會(huì)阻塞文檔解析,直到腳本執(zhí)行完才會(huì)繼續(xù)解析文檔。就是說(shuō)由于腳本是同步加載和執(zhí)行的,它會(huì)阻塞文檔解析,這也解釋了為什么現(xiàn)在通常建議將標(biāo)簽放在標(biāo)簽前面,而不是放在標(biāo)簽里?,F(xiàn)在HTML5提供defer和async兩個(gè)屬性支持延遲和異步加載JavaScript文件,如:
<script defer src="script.js">
改進(jìn)針對(duì)上文說(shuō)的腳本阻塞文檔解析,主流瀏覽器如Chrome和FireFox等都有一些優(yōu)化,比如在執(zhí)行腳本時(shí),開(kāi)啟另一個(gè)進(jìn)程解析剩余的文檔以找出并加載其他的待下載外部資源(不改變主進(jìn)程的DOM樹(shù),僅優(yōu)化加載外部資源)。
樣式不同于腳本,瀏覽器對(duì)樣式的處理并不會(huì)阻塞文檔解析,大概是因?yàn)闃邮奖聿⒉粫?huì)改變DOM結(jié)構(gòu)。
樣式表與腳本你可能想問(wèn)樣式是否會(huì)阻塞腳本文件的加載執(zhí)行呢?正常情況是不會(huì)的,但是存在一個(gè)問(wèn)題是通常我們會(huì)在腳本中請(qǐng)求樣式信息,但是在文檔解析時(shí),如果樣式尚未加載或解析,將會(huì)得到錯(cuò)誤信息,對(duì)于這一問(wèn)題,F(xiàn)ireFox瀏覽器和Webkit瀏覽器處理策略不同:
當(dāng)存在有樣式文件未被加載和解析時(shí),F(xiàn)ireFox瀏覽器會(huì)阻塞所有腳本;
而Webkit瀏覽器只會(huì)阻塞操作了改文件內(nèi)聲明的樣式屬性的腳本。
構(gòu)建DOM樹(shù)
DOM,即文檔對(duì)象模型(Document Object Model),DOM樹(shù),即文檔內(nèi)所有節(jié)點(diǎn)構(gòu)成的一個(gè)樹(shù)形結(jié)構(gòu)。
假設(shè)瀏覽器獲取返回的如下HTML文檔:
<!doctype html> <html> <head> <link rel="stylesheet" href="./theme.css"></link> <script src="./config.js"></script> <title>關(guān)鍵渲染路徑</title> </head> <body> <h2 class="title">關(guān)鍵渲染路徑</h2> <p>關(guān)鍵渲染路徑介紹</p> <footer>@copyright2017</footer> </body> </html>
首先瀏覽器從上到下依次解析文檔構(gòu)建DOM樹(shù),如下:
構(gòu)建CSSOM樹(shù)
CSSOM,即CSS對(duì)象模型(CSS Object Model),CSSOM樹(shù),與DOM樹(shù)結(jié)構(gòu)相似,只是另外為每一個(gè)節(jié)點(diǎn)關(guān)聯(lián)了樣式信息。
theme.css樣式內(nèi)容如下:
html, body { width: 100%; height: 100%; background-color: #fcfcfc; } .title { font-size: 20px; } .footer { font-size: 12px; color: #aaa; }
構(gòu)建CSSOM樹(shù)如圖:
執(zhí)行JavaScript
上文已經(jīng)闡述了文檔解析時(shí)對(duì)腳本的處理,我們得知腳本加載,解析和執(zhí)行會(huì)阻塞文檔解析,而在特殊情況下樣式的加載和解析也會(huì)阻塞腳本,所以現(xiàn)在推薦的實(shí)踐是標(biāo)簽放在標(biāo)簽前面。
構(gòu)建渲染樹(shù)(render tree)
DOM樹(shù)和CSSOM樹(shù)都構(gòu)建完了,接著瀏覽器會(huì)構(gòu)建渲染樹(shù):
渲染樹(shù),代表一個(gè)文檔的視覺(jué)展示,瀏覽器通過(guò)它將文檔內(nèi)容繪制在瀏覽器窗口,展示給用戶(hù),它由按順序展示在屏幕上的一系列矩形對(duì)象組成,這些矩形對(duì)象都帶有字體,顏色和尺寸,位置等視覺(jué)樣式屬性。對(duì)于這些矩對(duì)象,F(xiàn)ireFox稱(chēng)之為框架(frame),Webkit瀏覽器稱(chēng)之為渲染對(duì)象(render object, renderer),后文統(tǒng)稱(chēng)為渲染對(duì)象。
這里把渲染樹(shù)節(jié)點(diǎn)稱(chēng)為矩形對(duì)象,是因?yàn)?,每一個(gè)渲染對(duì)象都代表著其對(duì)應(yīng)DOM節(jié)點(diǎn)的CSS盒子,該盒子包含了尺寸,位置等幾何信息,同時(shí)它指向一個(gè)樣式對(duì)象包含其他視覺(jué)樣式信息。
渲染樹(shù)與DOM樹(shù)
每一個(gè)渲染對(duì)象都對(duì)應(yīng)著DOM節(jié)點(diǎn),但是非視覺(jué)(隱藏,不占位)DOM元素不會(huì)插入渲染樹(shù),如元素或聲明display: none;的元素,渲染對(duì)象與DOM節(jié)點(diǎn)不是簡(jiǎn)單的一對(duì)一的關(guān)系,一個(gè)DOM可以對(duì)應(yīng)一個(gè)渲染對(duì)象,但一個(gè)DOM元素也可能對(duì)應(yīng)多個(gè)渲染對(duì)象,因?yàn)橛泻芏嘣夭恢拱粋€(gè)CSS盒子,如當(dāng)文本被折行時(shí),會(huì)產(chǎn)生多個(gè)行盒,這些行會(huì)生成多個(gè)渲染對(duì)象;又如行內(nèi)元素同時(shí)包含塊元素和行內(nèi)元素,則會(huì)創(chuàng)建一個(gè)匿名塊級(jí)盒包含內(nèi)部行內(nèi)元素,此時(shí)一個(gè)DOM對(duì)應(yīng)多個(gè)矩形對(duì)象(渲染對(duì)象)。
渲染樹(shù)及其對(duì)應(yīng)DOM樹(shù)如圖:
圖中渲染樹(shù)viewport即視口,是文檔的初始包含塊,scroll代表滾動(dòng)區(qū)域,詳見(jiàn)CSS之視覺(jué)格式化模型(Visual Formatting Model)
渲染樹(shù)并不會(huì)包含顯式或隱式地display:none;的標(biāo)簽元素。
布局(Layout)或回流(reflow,relayout)
創(chuàng)建渲染樹(shù)后,下一步就是布局(Layout),或者叫回流(reflow,relayout),這個(gè)過(guò)程就是通過(guò)渲染樹(shù)中渲染對(duì)象的信息,計(jì)算出每一個(gè)渲染對(duì)象的位置和尺寸,將其安置在瀏覽器窗口的正確位置,而有些時(shí)候我們會(huì)在文檔布局完成后對(duì)DOM進(jìn)行修改,這時(shí)候可能需要重新進(jìn)行布局,也可稱(chēng)其為回流,本質(zhì)上還是一個(gè)布局的過(guò)程,每一個(gè)渲染對(duì)象都有一個(gè)布局或者回流方法,實(shí)現(xiàn)其布局或回流。
流(flow)
HTML采用的是基于流的方式定位布局,其按照從左到右,從上到下的順序進(jìn)行排列,詳見(jiàn)CSS定位機(jī)制。
全局布局與局部布局
對(duì)渲染樹(shù)的布局可以分為全局和局部的,全局即對(duì)整個(gè)渲染樹(shù)進(jìn)行重新布局,如當(dāng)我們改變了窗口尺寸或方向或者是修改了根元素的尺寸或者字體大小等;而局部布局可以是對(duì)渲染樹(shù)的某部分或某一個(gè)渲染對(duì)象進(jìn)行重新布局。
臟位系統(tǒng)(dirty bit system)
大多數(shù)web應(yīng)用對(duì)DOM的操作都是比較頻繁,這意味著經(jīng)常需要對(duì)DOM進(jìn)行布局和回流,而如果僅僅是一些小改變,就觸發(fā)整個(gè)渲染樹(shù)的回流,這顯然是不好的,為了避免這種情況,瀏覽器使用了臟位系統(tǒng),只有一個(gè)渲染對(duì)象改變了或者某渲染對(duì)象及其子渲染對(duì)象臟位值為”dirty”時(shí),說(shuō)明需要回流。
表示需要布局的臟位值有兩種:
“dirty”–自身改變,需要回流
“children are dirty”–子節(jié)點(diǎn)改變,需要回流
布局過(guò)程
布局是一個(gè)從上到下,從外到內(nèi)進(jìn)行的遞歸過(guò)程,從根渲染對(duì)象,即對(duì)應(yīng)著HTML文檔根元素,然后下一級(jí)渲染對(duì)象,如對(duì)應(yīng)著元素,如此層層遞歸,依次計(jì)算每一個(gè)渲染對(duì)象的幾何信息(位置和尺寸)。
幾何信息-位置和尺寸,即相對(duì)于窗口的坐標(biāo)和尺寸,如根渲染對(duì)象,其坐標(biāo)為(0, 0),尺寸即是視口
尺寸(瀏覽器窗口的可視區(qū)域)。
每一個(gè)渲染對(duì)象的布局流程基本如:
1.計(jì)算此渲染對(duì)象的寬度(width);
2.遍歷此渲染對(duì)象的所有子級(jí),依次:
a.設(shè)置子級(jí)渲染對(duì)象的坐標(biāo)
b.判斷是否需要觸發(fā)子渲染對(duì)象的布局或回流方法,計(jì)算子渲染對(duì)象的高度(height)
3.設(shè)置此渲染對(duì)象的高度:根據(jù)子渲染對(duì)象的累積高,margin和padding的高度設(shè)置其高度;
4.設(shè)置此渲染對(duì)象臟位值為false。
強(qiáng)制回流
在渲染樹(shù)布局完成后,再次操作文檔,改變文檔的內(nèi)容或結(jié)構(gòu),或者元素定位時(shí),會(huì)觸發(fā)回流,即需要重新布局,如請(qǐng)求某DOM的”offsetHeight”樣式信息等諸多情況:
DOM操作,如增加,刪除,修改或移動(dòng);
變更內(nèi)容;
激活偽類(lèi);
訪(fǎng)問(wèn)或改變某些CSS屬性(包括修改樣式表或元素類(lèi)名或使用JavaScript操作等方式);
瀏覽器窗口變化(滾動(dòng)或尺寸變化)
$('body').css('padding'); // reflow $('body')[0].offsetHeight; // relow
有過(guò)CSS3動(dòng)畫(huà)開(kāi)發(fā)經(jīng)驗(yàn)的同學(xué)可能會(huì)有經(jīng)歷,如下入場(chǎng)動(dòng)畫(huà):
.slide-left { -webkit-transition: margin-left 1s ease-out; -moz-transition: margin-left 1s ease-out; -o-transition: margin-left 1s ease-out; transition: margin-left 1s ease-out; }
然后執(zhí)行如下腳本:
var $slide = $('.slide-left'); $slide.css({ "margin-left": "100px" }).addClass('slide-left'); $slide.css({ "margin-left": "10px" });
我們會(huì)發(fā)現(xiàn)并沒(méi)有效果,為什么呢?因?yàn)閷?duì)margin-left的修改并沒(méi)有觸發(fā)回流,元素margin-left值的改變被緩存,如果我們?cè)谥虚g強(qiáng)制觸發(fā)回流:
var $slide = $('.slide-left'); $slide.css({ "margin-left": "100px" }); console.log($slide.css('padding'); $slide.addClass('slide-left'); $slide.css({ "margin-left": "10px" });
再看就達(dá)到了預(yù)期效果。
繪制(painting)
***是繪制(paint)階段或重繪(repaint)階段,瀏覽器UI組件將遍歷渲染樹(shù)并調(diào)用渲染對(duì)象的繪制(paint)方法,將內(nèi)容展現(xiàn)在屏幕上,也有可能在之后對(duì)DOM進(jìn)行修改,需要重新繪制渲染對(duì)象,也就是重繪,繪制和重繪的關(guān)系可以參考布局和回流的關(guān)系。
全局與局部繪制
與布局相似,繪制也分為全局和局部繪制,即對(duì)整個(gè)渲染樹(shù)或某些渲染對(duì)象進(jìn)行繪制。
觸發(fā)重繪
我們已經(jīng)知道很多操作可能會(huì)觸發(fā)回流,那么什么時(shí)候可能觸發(fā)重繪呢,通常,當(dāng)改變?cè)氐囊曈X(jué)樣式,如background-color,visibility,margin,padding或字體顏色時(shí)會(huì)觸發(fā)全局或局部重繪,如:
$('body').css('color', 'red'); // repaint $('body').css('margin', '2px'); // reflow, repaint
頁(yè)面渲染優(yōu)化
在改變文檔根元素的字體顏色等視覺(jué)性信息時(shí),會(huì)觸發(fā)整個(gè)文檔的重繪,而改變某元素的字體顏色則只觸發(fā)特定元素的重繪;改變?cè)氐奈恢眯畔?huì)同時(shí)觸發(fā)此元素(可能還包括其兄弟元素或子級(jí)元素)的布局和重繪。某些重大改變,如更改文檔根元素的字體尺寸,則會(huì)觸發(fā)整個(gè)文檔的重新布局和重繪,據(jù)此及上文所述,推薦以下優(yōu)化和實(shí)踐:
1.HTML文檔結(jié)構(gòu)層次盡量少,***不深于六層;
2.腳本盡量后放,放在前即可;
3.少量首屏樣式內(nèi)聯(lián)放在標(biāo)簽內(nèi);
4.樣式結(jié)構(gòu)層次盡量簡(jiǎn)單;
5.在腳本中盡量減少DOM操作,盡量緩存訪(fǎng)問(wèn)DOM的樣式信息,避免過(guò)度觸發(fā)回流;
6.減少通過(guò)JavaScript代碼修改元素樣式,盡量使用修改class名方式操作樣式或動(dòng)畫(huà);
7.動(dòng)畫(huà)盡量使用在絕對(duì)定位或固定定位的元素上;
8.隱藏在屏幕外,或在頁(yè)面滾動(dòng)時(shí),盡量停止動(dòng)畫(huà);
9.盡量緩存DOM查找,查找器盡量簡(jiǎn)潔;
10.涉及多域名的網(wǎng)站,可以開(kāi)啟域名預(yù)解析
實(shí)例
當(dāng)我們?cè)L問(wèn)一個(gè)頁(yè)面時(shí),瀏覽器渲染事件詳細(xì)日志圖如下:
發(fā)起請(qǐng)求;
解析HTML;
解析樣式;
執(zhí)行JavaScript;
布局;
繪制
“web前端頁(yè)面渲染機(jī)制是什么”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。