到目前爲止,在咱們以前的「JavaScript工做原理」系列文章中,咱們一直關注JavaScript做爲一種語言,其功能,它如何在瀏覽器中執行,如何優化等等。css
可是,當您構建Web應用程序時,您不僅是編寫獨立運行的獨立JavaScript代碼。您編寫的JavaScript與環境進行交互。瞭解這種環境,它是如何工做的以及它的組成是什麼,將使您可以構建更好的應用程序,並對應用程序發佈後可能出現的潛在問題作好充分準備。
html
那麼,讓咱們看看瀏覽器的主要組件是什麼:node
在這篇文章中,咱們將關注渲染引擎,由於它處理HTML和CSS的解析和可視化,這是大多數JavaScript應用程序不斷與之交互的東西。git
渲染引擎的主要職責是在瀏覽器屏幕上顯示請求的頁面。github
渲染引擎能夠顯示HTML和XML文檔和圖像。若是您使用額外的插件,引擎還能夠顯示不一樣類型的文檔,如PDF。web
與JavaScript引擎相似,不一樣的瀏覽器也使用不一樣的渲染引擎。這些是一些流行的:後端
渲染引擎從網絡層接收所請求文檔的內容。
瀏覽器
構建DOM樹
渲染引擎的第一步是解析HTML文檔並將解析的元素轉換爲DOM樹中的實際DOM節點。網絡
想象一下你有如下的文字輸入:框架
<html> <head> <meta charset="UTF-8"> <link rel="stylesheet" type="text/css" href="theme.css"> </head> <body> <p> Hello, <span> friend! </span> </p> <div> <img src="smiley.gif" alt="Smiley face" height="42" width="42"> </div> </body> </html>
這個HTML的DOM樹以下所示:
基本上,每一個元素都被表示爲全部其子元素的父節點子元素直接包含在它的內部。
CSSOM指的是CSS對象模型。當瀏覽器構建頁面的DOM時,它在引用外部theme.css CSS樣式表的head部分遇到link標記。預計它可能須要該資源來呈現頁面,它當即發出請求。假設theme.css文件包含如下內容:
body { font-size: 16px; } p { font-weight: bold; } span { color: red; } p span { display: none; } img { float: right; }
與HTML同樣,引擎須要將CSS轉換爲瀏覽器可使用的東西 - CSSOM。 如下是CSSOM樹的外觀:
你想知道爲何CSSOM有一個樹結構?當計算頁面上任何對象的最後一組樣式時,瀏覽器從適用於該節點的最通常規則開始(例如,若是它是body元素的子元素,則應用全部body樣式),而後遞歸地細化經過應用更具體的規則來計算樣式。
讓咱們來看看咱們給出的具體例子。包含在body元素中的span標籤中的任何文本的字體大小爲16像素,而且具備紅色。這些樣式是從body元素繼承而來的。若是span元素是p元素的子元素,則因爲正在應用更具體的樣式,所以不會顯示其內容。
另外請注意,上面的樹不是完整的CSSOM樹,只顯示了咱們決定在樣式表中重寫的樣式。每一個瀏覽器都提供了一組默認的樣式,也稱爲「user agent styles」 - 這是咱們在沒有明確提供任何樣式時看到的。咱們的樣式簡單地覆蓋這些默認值。
HTML中的可視指令與CSSOM樹中的樣式數據結合在一塊兒用於建立渲染樹。
你可能會問什麼是渲染樹?這是按照它們在屏幕上顯示的順序構建的視覺元素樹。它是HTML和相應的CSS的可視化表示。此樹的目的是爲了以正確的順序繪製內容。
Webkit中,渲染樹中的每一個節點都被稱爲的渲染器或渲染對象。
這就是上述DOM和CSSOM樹的渲染器樹的外觀:
爲了構建渲染樹,瀏覽器大體以下:
你能夠在這裏看看RenderObject的源代碼(在WebKit中):https://github.com/WebKit/web...
咱們來看看這個類的一些核心內容:
class RenderObject : public CachedImageClient { // Repaint the entire object. Called when, e.g., the color of a border changes, or when a border // style changes. Node* node() const { ... } RenderStyle* style; // the computed style const RenderStyle& style() const; ... }
每一個渲染器表明一個矩形區域,一般對應於一個節點的CSS框。它包括幾何信息,例如寬度,高度和位置。
當渲染器被建立並添加到樹中時,它沒有位置和大小。計算這些值稱爲佈局。
HTML使用基於流程的佈局模型,這意味着大部分時間內它能夠經過一次傳遞計算幾何。座標系相對於根渲染器。使用頂部和左側座標。
佈局是一個遞歸過程 - 它從根呈現器開始,它對應於HTML文檔的<html>元素。佈局經過部分或整個渲染器層次結構遞歸地繼續遞歸,爲須要它的每一個渲染器計算幾何信息。
根渲染器的位置是0,0,而且其尺寸具備瀏覽器窗口(也稱爲視口)的可見部分的尺寸。
開始佈局過程意味着給每一個節點確切的座標,它應該出如今屏幕上。
在此階段中,遍歷渲染器樹並調用渲染器的paint()方法以在屏幕上顯示內容。
繪畫能夠是全局或增量式(與佈局相似):
通常來講,瞭解繪畫是一個漸進的過程是很重要的。爲了更好的用戶體驗,渲染引擎會嘗試儘快在屏幕上顯示內容。它不會等到全部的HTML被解析,纔開始構建和佈置渲染樹。內容的部份內容將被解析並顯示,而該過程繼續保持來自網絡的其他內容項目。
當解析器到達<script>標記時,腳本將被當即解析並執行。文檔解析暫停,直到腳本執行完畢。這意味着該過程是同步的。
若是腳本是外部的,那麼它首先必須從網絡中獲取(也是同步的)。全部解析都會中止,直到抓取完成。
HTML5添加了一個選項,將腳本標記爲異步,以便它能夠被其餘線程解析和執行。
若是您想優化您的應用,那麼您須要關注五個主要方面。這些是您能夠控制的區域:
JavaScript常常觸發瀏覽器中的視覺變化。當創建一個SPA時更是如此。
如下是關於JavaScript能夠優化哪些部分以改善渲染的一些提示:
經過添加和刪除元素,更改屬性等來修改DOM將使瀏覽器從新計算元素樣式,而且在不少狀況下還會整個頁面的佈局或至少部分佈局。
要優化渲染,請考慮如下幾點:
瀏覽器的佈局從新計算可能很是繁重。考慮如下優化:
這一般是全部任務中運行時間最長的,所以儘量避免這種狀況很是重要。如下是咱們能夠作的事情: