新聞中心
當(dāng)你構(gòu)建 Web 應(yīng)用程序時(shí),你不只是編寫單獨(dú)運(yùn)行的 JavaScript 代碼,你編寫的 JavaScript 正在與環(huán)境進(jìn)行交互。了解這種環(huán)境,它的工作原理以及它的組,這些有助于你夠構(gòu)建更好的應(yīng)用程序,并為應(yīng)用程序發(fā)布后可能出現(xiàn)的潛在問(wèn)題做好充分準(zhǔn)備。

我們提供的服務(wù)有:成都做網(wǎng)站、成都網(wǎng)站設(shè)計(jì)、微信公眾號(hào)開(kāi)發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認(rèn)證、中山ssl等。為1000多家企事業(yè)單位解決了網(wǎng)站和推廣的問(wèn)題。提供周到的售前咨詢和貼心的售后服務(wù),是有科學(xué)管理、有技術(shù)的中山網(wǎng)站制作公司
瀏覽器的主要組件包括:
- 用戶界面 (User interface): 包括地址欄、后退/前進(jìn)按鈕、書簽?zāi)夸浀?,也就是你所看到的除了用?lái)顯示你所請(qǐng)求頁(yè)面的主窗口之外的其他部分
- 瀏覽器引擎 (Browser engine): 用來(lái)查詢及操作渲染引擎的接口
- 渲染引擎 (Rendering engine): 用來(lái)顯示請(qǐng)求的內(nèi)容,例如,如果請(qǐng)求內(nèi)容為 html,它負(fù)責(zé)解析 html 及 css,并將解析后的結(jié)果顯示出來(lái)
- 網(wǎng)絡(luò) (Networking): 用來(lái)完成網(wǎng)絡(luò)調(diào)用,例如http請(qǐng)求,它具有平臺(tái)無(wú)關(guān)的接口,可以在不同平臺(tái)上工作
- UI 后端 (UI backend): 用來(lái)繪制類似組合選擇框及對(duì)話框等基本組件,具有不特定于某個(gè)平臺(tái)的通用接口,底層使用操作系統(tǒng)的用戶接口
- JS 解釋器 (JavaScript engine): 用來(lái)解釋執(zhí)行JS代碼
- 數(shù)據(jù)存儲(chǔ) (Data persistence): 屬于持久層,瀏覽器需要在硬盤中保存類似 cookie 的各種數(shù)據(jù),HTML5定義了 Web Database 技術(shù),這是一種輕量級(jí)完整的客戶端存儲(chǔ)技術(shù),支持的存儲(chǔ)機(jī)制類型包括 localStorage 、 indexDB 、 WebSQL 和 FileSystem 。
在這篇文章中,將重點(diǎn)討論渲染引擎,因?yàn)樗幚?HTML 和 CSS 的解析和可視化,這是大多數(shù) JavaScript 應(yīng)用程序經(jīng)常與之交互的東西。
渲染引擎概述
渲染引擎的職責(zé)就是渲染,即在瀏覽器窗口中顯示所請(qǐng)求的內(nèi)容。
渲染引擎可以顯示 HTML 和 XML 文檔和圖像。如果使用其他插件,渲染引擎還可以顯示不同類型的文檔,如 PDF。
渲染引擎 (Rendering engines)
與 JavaScript 引擎類似,不同的瀏覽器也使用不同的渲染引擎。以下是一些最受歡迎的:
- Gecko — Firefox
- WebKit — Safari
- Blink — Chrome,Opera (版本 15 之后)
Firefox、Chrome 和 Safari 是基于兩種渲染引擎構(gòu)建的,F(xiàn)irefox 使用 Geoko——Mozilla 自主研發(fā)的渲染引擎,Safari 和 Chrome 都使用 Webkit。Blink 是 Chrome 基于 WebKit的自主渲染引擎。
渲染的過(guò)程
渲染引擎從網(wǎng)絡(luò)層接收所請(qǐng)求文檔的內(nèi)容。
解析 HTML 以構(gòu)建 Dom 樹(shù) -> 構(gòu)建 Render 樹(shù) -> 布局 Render 樹(shù) -> 繪制 Render 樹(shù)
構(gòu)建 Dom 樹(shù)
渲染現(xiàn)引擎的第一步是解析 HTML文檔,并將解析后的元素轉(zhuǎn)換為 DOM 樹(shù) 中的實(shí)際 DOM 節(jié)點(diǎn)。
假如有如下 Html 結(jié)構(gòu)
Hello, friend!
![]()
對(duì)應(yīng)的 DOM樹(shù)如下:
基本上,每個(gè)元素都表示為所有元素的父節(jié)點(diǎn),這些元素直接包含在元素中。
構(gòu)建 CSSOM
CSSOM 指的是 CSS 對(duì)象模型 。 當(dāng)瀏覽器構(gòu)建頁(yè)面的 DOM 時(shí),它在 head 標(biāo)簽下如遇到了一個(gè) link 標(biāo)記且引用了外部 theme.css CSS 樣式表。 瀏覽器預(yù)計(jì)可能需要該資源來(lái)呈現(xiàn)頁(yè)面,它會(huì)立即發(fā)送請(qǐng)求。 假設(shè) theme.css 文件內(nèi)容如下:
- body {
- font-size: 16px;
- }
- p {
- font-weight: bold;
- }
- span {
- color: red;
- }
- p span {
- display: none;
- }
- img {
- float: right;
- }
與 HTML一樣,渲染引擎需要將 CSS 轉(zhuǎn)換成瀏覽器可以使用的東西—— CSSOM。CSSOM 結(jié)構(gòu)如下:
你想知道為什么 CSSOM 是一個(gè)樹(shù)形結(jié)構(gòu)? 在為頁(yè)面上的任何對(duì)象計(jì)算最終樣式集時(shí),瀏覽器以適用于該節(jié)點(diǎn)的最常規(guī)規(guī)則開(kāi)始(例如,如果它是 body 元素的子元素,則應(yīng)用所有 body 樣式),然后遞歸地細(xì)化,通過(guò)應(yīng)用更具體的規(guī)則來(lái)計(jì)算樣式。
來(lái)看看具體的例子。包含在 body 元素內(nèi)的 span 標(biāo)簽中的任何文本的字體大小均為 16 像素,并且為紅色。這些樣式是從 body 元素繼承而來(lái)的。 如果一個(gè) span 元素是一個(gè) p 元素的子元素,那么它的內(nèi)容就不會(huì)被顯示,因?yàn)樗粦?yīng)用了更具體的樣式(display: none)。
另請(qǐng)注意,上面的樹(shù)不是完整的 CSSOM 樹(shù),只顯示我們決定在樣式表中覆蓋的樣式。 每個(gè)瀏覽器都提供一組默認(rèn)樣式,也稱為 “user agent stylesheet” 。這是我們?cè)谖疵鞔_指定任何樣式時(shí)看到的樣式,我們的樣式會(huì)覆蓋這些默認(rèn)值。
不同瀏覽器對(duì)于相同元素的默認(rèn)樣式并不一致,這也是為什么我們?cè)?CSS 的最開(kāi)始要寫 *{padding:0;marging:0}; ,也就是我們要重置CSS默認(rèn)樣式的。
構(gòu)建渲染樹(shù)
CSSOM 樹(shù)和 DOM 樹(shù)連接在一起形成一個(gè) render tree,渲染樹(shù)用來(lái)計(jì)算可見(jiàn)元素的布局并且作為將像素渲染到屏幕上的過(guò)程的輸入。
- DOM 樹(shù)和 CSSOM 樹(shù)連接在一起形成 render tree .
- render tree 只包含了用于渲染頁(yè)面的節(jié)點(diǎn)
- 布局計(jì)算了每一個(gè)對(duì)象的準(zhǔn)確的位置以及大小
- 繪畫是最后一步,繪畫要求利用 render tree 來(lái)將像素顯示到屏幕上
渲染樹(shù)中的每個(gè)節(jié)點(diǎn)在 Webkit 中稱為渲染器或渲染對(duì)象。
收下是上面 DOM 和 CSSOM 樹(shù)的渲染器樹(shù)的樣子:
為了構(gòu)建渲染樹(shù),瀏覽器大致執(zhí)行以下操作:
從 DOM 樹(shù)根節(jié)點(diǎn)開(kāi)始,遍歷每一個(gè)可見(jiàn)的節(jié)點(diǎn)
- display:none
- 對(duì)每一個(gè)可見(jiàn)的節(jié)點(diǎn),找到合適的匹配的CSSOM規(guī)則,并且應(yīng)用樣式
- 顯示可見(jiàn)節(jié)點(diǎn)(節(jié)點(diǎn)包括內(nèi)容和被計(jì)算的樣式)
“visibility:hidden” 和 “display:none” 之間的不同, “visibility:hidden” 將元素設(shè)置為不可見(jiàn),但是同樣在布局上占領(lǐng)一定空間(例如,它會(huì)被渲染成為空盒子),但是 “display:none” 的元素是將節(jié)點(diǎn)從整個(gè) render tree 中移除,所以不是布局中的一部分 。
你可以在這里查看 RenderObject 的源代碼(在 WebKit 中):
https://github.com/WebKit/web...
我們來(lái)看看這個(gè)類的一些核心內(nèi)容:
每個(gè)渲染器代表一個(gè)矩形區(qū)域,通常對(duì)應(yīng)于一個(gè)節(jié)點(diǎn)的 CSS 盒模型。它包含幾何信息,例如寬度、高度和位置。
渲染樹(shù)的布局
創(chuàng)建渲染器并將其添加到樹(shù)中時(shí),它沒(méi)有位置和大小,計(jì)算這些值稱為布局。
HTML使用基于流的布局模型,這意味著大多數(shù)時(shí)間它可以一次性計(jì)算幾何圖形。坐標(biāo)系統(tǒng)相對(duì)于根渲染器,使用左上原點(diǎn)坐標(biāo)。
布局是一個(gè)遞歸過(guò)程 - 它從根渲染器開(kāi)始,它對(duì)應(yīng)于 HTML 文檔的 元素。 布局以遞歸方式繼續(xù)通過(guò)部件或整個(gè)渲染器層次結(jié)構(gòu),為每個(gè)需要它的渲染器計(jì)算幾何信息。
根渲染器的位置為 0,0 ,其尺寸與瀏覽器窗口的可見(jiàn)部分(即viewport)的大小相同。開(kāi)始布局過(guò)程意味著給每個(gè)節(jié)點(diǎn)在屏幕上應(yīng)該出現(xiàn)的確切坐標(biāo)。
繪制渲染樹(shù)
在此繪制,遍歷渲染器樹(shù)并調(diào)用渲染器的 paint() 方法以在屏幕上顯示內(nèi)容。
繪圖可以是全局的或增量式的(與布局類似):
- 全局 — 整棵樹(shù)被重繪
- 增量式 — 只有一些渲染器以不影響整個(gè)樹(shù)的方式改變。 渲染器使其在屏幕上的矩形無(wú)效,這會(huì)導(dǎo)致操作系統(tǒng)將其視為需要重新繪制并生成繪
paint事件的區(qū)域。 操作系統(tǒng)通過(guò)將多個(gè)區(qū)域合并為一個(gè)來(lái)智能完成。
總的來(lái)說(shuō),重要的中要理解繪圖是一個(gè)漸進(jìn)的過(guò)程。為了更好的用戶體驗(yàn),渲染引擎將盡可能快地在屏幕上顯示內(nèi)容。它不會(huì)等到解析完所有 HTML 后才開(kāi)始構(gòu)建和布局渲染樹(shù),而是解析和顯示部分內(nèi)容,同時(shí)繼續(xù)處理來(lái)自網(wǎng)絡(luò)的其余內(nèi)容項(xiàng)。
處理腳本和樣式表的順序
當(dāng)解析器到達(dá) 標(biāo)記時(shí),將立即解析并執(zhí)行腳本。文檔的解析將暫停,直到執(zhí)行腳本為止。這意味著這個(gè)過(guò)程是 同步的 。
如果腳本是外部的,那么首先必須從網(wǎng)絡(luò)中獲取它(也是同步的)。所有解析都停止,直到獲取完成。HTML5 新加了async 或 defer 屬性,將腳本標(biāo)記為異步的,以便由不同的線程解析和執(zhí)行。
優(yōu)化渲染性能
如果你想優(yōu)化自己的應(yīng)用,則需要關(guān)注五個(gè)主要方面,這些是你自己可以控制的:
- JavaScript — 在之前的文章中,討論了如果編寫優(yōu)化代碼的主題抱包括如果編寫代碼才不會(huì)阻止UI,和提高內(nèi)存利用等等。在渲染時(shí),需要考慮 JavaScript 代碼與頁(yè)面 上DOM 素交互的方式。 JavaScript 可以在 UI中創(chuàng)建大量更改,尤其是在 SPA 中。
- 樣式計(jì)算 — 這是根據(jù)匹配選擇器確定哪個(gè) CSS 規(guī)則適用于哪個(gè)元素的過(guò)程。 定義規(guī)則后,將應(yīng)用它們并計(jì)算每個(gè)元素的最終樣式。
- 布局 — 一旦瀏覽器知道哪些規(guī)則適用于某個(gè)元素,它就可以開(kāi)始計(jì)算后者占用多少空間以及它在瀏覽器屏幕上的位置。Web 的布局模型定義了一個(gè)元素可以影響其他元素。例如, 的寬度會(huì)影響其子元素的寬度,等等。這意味著布局過(guò)程是計(jì)算密集型的,該繪圖是在多個(gè)圖層完成的。
- 繪圖 —— 這是實(shí)際像素被填充的地方,這個(gè)過(guò)程包括繪制文本、顏色、圖像、邊框、陰影等——每個(gè)元素的每個(gè)可視部分。
- 合成 — 由于頁(yè)面部分可能被繪制成多個(gè)層,因此它們需要以正確的順序繪制到屏幕上,以便頁(yè)面渲染正確。這是非常重要的,特別是對(duì)于重疊的元素。
優(yōu)化你的 JavaScript
JavaScript 經(jīng)常觸發(fā)瀏覽器中的視覺(jué)變化,構(gòu)建 SPA 時(shí)更是如此。
以下是一些優(yōu)化 JavaScript 渲染技巧:
- 避免使用
setTimeout或setInterval進(jìn)行可視更新。 這些將在幀中的某個(gè)點(diǎn)調(diào)用callback,可能在最后。我們想要做的是在幀開(kāi)始時(shí)觸發(fā)視覺(jué)變化而不是錯(cuò)過(guò)它。 - 如之前文章 所述,將長(zhǎng)時(shí)間運(yùn)行的 JavaScript 計(jì)算轉(zhuǎn)移到 Web Workers。
- 使用微任務(wù)在多個(gè)幀中變更 DOM。這是在任務(wù)需要訪問(wèn) DOM 時(shí)使用的, Web Worker 無(wú)法訪問(wèn) DOM。這基本上意味著你要把一個(gè)大任務(wù)分解成更小的任務(wù),然后根據(jù)任務(wù)的性質(zhì)在
requestAnimationFrame,setTimeout,setInterval中運(yùn)行它們。
優(yōu)化你的 CSS
通過(guò)添加和刪除元素,更改屬性等來(lái)修改 DOM 將使瀏覽器重新計(jì)算元素樣式,并且在許多情況下,重新計(jì)算整個(gè)頁(yè)面的布局或至少部分布局。
要優(yōu)化渲染,考慮以下事項(xiàng):
- 減少選擇器的復(fù)雜性,與構(gòu)造樣式本身的其他工作相比,選擇器復(fù)雜性可以占用計(jì)算元素樣式所需時(shí)間的50%以上。
*減少必須進(jìn)行樣式計(jì)算的元素的數(shù)量。本質(zhì)上,直接對(duì)一些元素進(jìn)行樣式更改,而不是使整個(gè)頁(yè)面無(wú)效。
優(yōu)化布局
瀏覽器的布局重新計(jì)算可能非常繁重。 考慮以下優(yōu)化:
- 盡可能減少布局的數(shù)量。當(dāng)你更改樣式時(shí),瀏覽器會(huì)檢查是否有任何更改需要重新計(jì)算布局。對(duì)寬度、高度、左、頂?shù)葘傩缘母?,以及通常與幾何相關(guān)的屬性的更改,都需要布局。所以,盡量避免改變它們。
- 盡量使用 flexbox 而不是老的布局模型。它運(yùn)行速度更快,可為你的應(yīng)用程序創(chuàng)造巨大的性能優(yōu)勢(shì)。
- 避免強(qiáng)制同步布局。需要記住的是,在 JavaScript 運(yùn)行時(shí),前一幀中的所有舊布局值都是已知的,可以查詢。如果你訪問(wèn)
box.offsetHeight,那就不成問(wèn)題了。但是,如果你在訪問(wèn)box之前更改了它的樣式(例如,通過(guò)動(dòng)態(tài)地向元素添加一些 CSS 類),瀏覽器必須先應(yīng)用樣式更改并執(zhí)行布局過(guò)程,這是非常耗時(shí)和耗費(fèi)資源的,所以盡可能避免。
優(yōu)化繪圖
這通常是所有任務(wù)中運(yùn)行時(shí)間最長(zhǎng)的,因此盡可能避免這種情況非常重要。 以下是我們可以做的事情:
- 除了變換(transform)和透明度之外,改變其他任何屬性都會(huì)觸發(fā)重新繪圖,請(qǐng)謹(jǐn)慎使用。
- 如果觸發(fā)了布局,那也會(huì)觸發(fā)繪圖,因?yàn)楦牟季謺?huì)導(dǎo)致元素的視覺(jué)效果也改變。
- 通過(guò)圖層提升和動(dòng)畫編排來(lái)減少重繪區(qū)域。
新聞名稱:JavaScript是如何工作的:渲染引擎和優(yōu)化其性能的技巧
標(biāo)題鏈接:http://m.fisionsoft.com.cn/article/dhsecps.html


咨詢
建站咨詢
