JavaScript是如何工做的:渲染引擎和優化其性能的技巧

摘要: 理解瀏覽器渲染。javascript

Fundebug經受權轉載,版權歸原做者全部。css

這是專門探索 JavaScript 及其所構建的組件的系列文章的第11篇。html

若是你錯過了前面的章節,能夠在這裏找到它們:前端

當你構建 Web 應用程序時,你不僅是編寫單獨運行的 JavaScript 代碼,你編寫的 JavaScript 正在與環境進行交互。瞭解這種環境,它的工做原理以及它的組,這些有助於你夠構建更好的應用程序,併爲應用程序發佈後可能出現的潛在問題作好充分準備。java

瀏覽器的主要組件包括:git

  • 用戶界面 (User interface): 包括地址欄、後退/前進按鈕、書籤目錄等,也就是你所看到的除了用來顯示你所請求頁面的主窗口以外的其餘部分
  • **瀏覽器引擎 (Browser engine):**用來查詢及操做渲染引擎的接口
  • **渲染引擎 (Rendering engine):**用來顯示請求的內容,例如,若是請求內容爲 html,它負責解析 html 及 css,並將解析後的結果顯示出來
  • **網絡 (Networking):**用來完成網絡調用,例如http請求,它具備平臺無關的接口,能夠在不一樣平臺上工做
  • **UI 後端 (UI backend):**用來繪製相似組合選擇框及對話框等基本組件,具備不特定於某個平臺的通用接口,底層使用操做系統的用戶接口
  • **JS 解釋器 (JavaScript engine):**用來解釋執行JS代碼
  • 數據存儲 (Data persistence): 屬於持久層,瀏覽器須要在硬盤中保存相似 cookie 的各類數據,HTML5定義了 Web Database 技術,這是一種輕量級完整的客戶端存儲技術,支持的存儲機制類型包括 localStorageindexDBWebSQLFileSystem

在這篇文章中,將重點討論渲染引擎,由於它處理 HTML 和 CSS 的解析和可視化,這是大多數 JavaScript 應用程序常常與之交互的東西。github

渲染引擎概述

渲染引擎的職責就是渲染,即在瀏覽器窗口中顯示所請求的內容。web

渲染引擎能夠顯示 HTML 和 XML 文檔和圖像。若是使用其餘插件,渲染引擎還能夠顯示不一樣類型的文檔,如 PDF。編程

渲染引擎 (Rendering engines)

與 JavaScript 引擎相似,不一樣的瀏覽器也使用不一樣的渲染引擎。如下是一些最受歡迎的:小程序

  • Gecko — Firefox
  • WebKit — Safari
  • Blink — Chrome,Opera (版本 15 以後)

Firefox、Chrome 和 Safari 是基於兩種渲染引擎構建的,Firefox 使用 Geoko——Mozilla 自主研發的渲染引擎,Safari 和 Chrome 都使用 Webkit。Blink 是 Chrome 基於 WebKit的自主渲染引擎。

渲染的過程

渲染引擎從網絡層接收所請求文檔的內容。

解析 HTML 以構建 Dom 樹 -> 構建 Render 樹 -> 佈局 Render 樹 -> 繪製 Render 樹

構建 Dom 樹

渲染現引擎的第一步是解析 HTML文檔,並將解析後的元素轉換爲 DOM 樹中的實際 DOM 節點。

假若有以下 Html 結構

<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>
複製代碼

對應的 DOM 樹以下:

基本上,每一個元素都表示爲全部元素的父節點,這些元素直接包含在元素中。

構建 CSSOM

CSSOM 指的是 CSS 對象模型。 當瀏覽器構建頁面的 DOM 時,它在 head 標籤下如遇到了一個 link 標記且引用了外部 theme.css CSS 樣式表。 瀏覽器預計可能須要該資源來呈現頁面,它會當即發送請求。 假設 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 元素的子元素,那麼它的內容就不會被顯示,由於它被應用了更具體的樣式(display: none)。

另請注意,上面的樹不是完整的 CSSOM 樹,只顯示咱們決定在樣式表中覆蓋的樣式。 每一個瀏覽器都提供一組默認樣式,也稱爲**「user agent stylesheet」**。這是咱們在未明確指定任何樣式時看到的樣式,咱們的樣式會覆蓋這些默認值。

不一樣瀏覽器對於相同元素的默認樣式並不一致,這也是爲何咱們在 CSS 的最開始要寫 *{padding:0;marging:0};,也就是咱們要重置CSS默認樣式的。

構建渲染樹

CSSOM 樹和 DOM 樹鏈接在一塊兒造成一個 render tree,渲染樹用來計算可見元素的佈局而且做爲將像素渲染到屏幕上的過程的輸入。

  • DOM 樹和 CSSOM 樹鏈接在一塊兒造成 render tree .
  • render tree 只包含了用於渲染頁面的節點
  • 佈局計算了每個對象的準確的位置以及大小
  • 繪畫是最後一步,繪畫要求利用 render tree 來將像素顯示到屏幕上

渲染樹中的每一個節點在 Webkit 中稱爲渲染器或渲染對象。

收下是上面 DOM 和 CSSOM 樹的渲染器樹的樣子:

爲了構建渲染樹,瀏覽器大體執行如下操做:

  • 從 DOM 樹根節點開始,遍歷每個可見的節點
    • 一些節點是徹底不可見的(好比 script標籤,meta標籤等),這些節點會被忽略,由於他們不會影響渲染的輸出
    • 一些節點是經過 CSS 樣式隱藏了,這些節點一樣被忽略——例如上例中的 span 節點在 render tree 中被忽略,由於 span 樣式是 display:none
  • 對每個可見的節點,找到合適的匹配的CSSOM規則,而且應用樣式
  • 顯示可見節點(節點包括內容和被計算的樣式)

「visibility:hidden」「display:none」 之間的不一樣,「visibility:hidden」 將元素設置爲不可見,可是一樣在佈局上佔領必定空間(例如,它會被渲染成爲空盒子),可是 「display:none」 的元素是將節點從整個 render tree 中移除,因此不是佈局中的一部分 。

你能夠在這裏查看 RenderObject 的源代碼(在 WebKit 中):

github.com/WebKit/web.…

咱們來看看這個類的一些核心內容:

每一個渲染器表明一個矩形區域,一般對應於一個節點的 CSS 盒模型。它包含幾何信息,例如寬度、高度和位置。

代碼部署後可能存在的BUG無法實時知道,過後爲了解決這些BUG,花了大量的時間進行log 調試,這邊順便給你們推薦一個好用的BUG監控工具Fundebug

渲染樹的佈局

建立渲染器並將其添加到樹中時,它沒有位置和大小,計算這些值稱爲佈局。

HTML使用基於流的佈局模型,這意味着大多數時間它能夠一次性計算幾何圖形。座標系統相對於根渲染器,使用左上原點座標。

佈局是一個遞歸過程 - 它從根渲染器開始,它對應於 HTML 文檔的 <html> 元素。 佈局以遞歸方式繼續經過部件或整個渲染器層次結構,爲每一個須要它的渲染器計算幾何信息。

根渲染器的位置爲0,0,其尺寸與瀏覽器窗口的可見部分(即viewport)的大小相同。開始佈局過程意味着給每一個節點在屏幕上應該出現的確切座標。

繪製渲染樹

在此繪製,遍歷渲染器樹並調用渲染器的 paint() 方法以在屏幕上顯示內容。

繪圖能夠是全局的或增量式的(與佈局相似):

  • 全局 — 整棵樹被重繪
  • 增量式 — 只有一些渲染器以不影響整個樹的方式改變。 渲染器使其在屏幕上的矩形無效,這會致使操做系統將其視爲須要從新繪製並生成繪 paint 事件的區域。 操做系統經過將多個區域合併爲一個來智能完成。

總的來講,重要的中要理解繪圖是一個漸進的過程。爲了更好的用戶體驗,渲染引擎將盡量快地在屏幕上顯示內容。它不會等到解析完全部 HTML 後纔開始構建和佈局渲染樹,而是解析和顯示部份內容,同時繼續處理來自網絡的其他內容項。

處理腳本和樣式表的順序

當解析器到達 <script> 標記時,將當即解析並執行腳本。文檔的解析將暫停,直到執行腳本爲止。這意味着這個過程是同步的

若是腳本是外部的,那麼首先必須從網絡中獲取它(也是同步的)。全部解析都中止,直到獲取完成。HTML5 新加了async 或 defer 屬性,將腳本標記爲異步的,以便由不一樣的線程解析和執行。

優化渲染性能

若是你想優化本身的應用,則須要關注五個主要方面,這些是你本身能夠控制的:

  1. JavaScript   — 在以前的文章中,討論了若是編寫優化代碼的主題抱包括若是編寫代碼纔不會阻止UI,和提升內存利用等等。在渲染時,須要考慮 JavaScript 代碼與頁面 上DOM 素交互的方式。 JavaScript 能夠在 UI中建立大量更改,尤爲是在 SPA 中。
  2. 樣式計算 — 這是根據匹配選擇器肯定哪一個 CSS 規則適用於哪一個元素的過程。 定義規則後,將應用它們並計算每一個元素的最終樣式。
  3. 佈局 — 一旦瀏覽器知道哪些規則適用於某個元素,它就能夠開始計算後者佔用多少空間以及它在瀏覽器屏幕上的位置。Web 的佈局模型定義了一個元素能夠影響其餘元素。例如, 的寬度會影響其子元素的寬度,等等。這意味着佈局過程是計算密集型的,該繪圖是在多個圖層完成的。
  4. 繪圖 —— 這是實際像素被填充的地方,這個過程包括繪製文本、顏色、圖像、邊框、陰影等——每一個元素的每一個可視部分。
  5. 合成  — 因爲頁面部分可能被繪製成多個層,所以它們須要以正確的順序繪製到屏幕上,以便頁面渲染正確。這是很是重要的,特別是對於重疊的元素。

優化你的 JavaScript

JavaScript 常常觸發瀏覽器中的視覺變化,構建 SPA 時更是如此。

如下是一些優化 JavaScript 渲染技巧:

  • 避免使用 setTimeoutsetInterval 進行可視更新。 這些將在幀中的某個點調用 callback ,可能在最後。咱們想要作的是在幀開始時觸發視覺變化而不是錯過它。
  • 以前文章 所述,將長時間運行的 JavaScript 計算轉移到 Web Workers。
  • 使用微任務在多個幀中變動 DOM。這是在任務須要訪問 DOM 時使用的, Web Worker 沒法訪問 DOM。這基本上意味着你要把一個大任務分解成更小的任務,而後根據任務的性質在 requestAnimationFrame, setTimeout, setInterval 中運行它們。

優化你的 CSS

經過添加和刪除元素,更改屬性等來修改 DOM 將使瀏覽器從新計算元素樣式,而且在許多狀況下,從新計算整個頁面的佈局或至少部分佈局。

要優化渲染,考慮如下事項:

  • 減小選擇器的複雜性,與構造樣式自己的其餘工做相比,選擇器複雜性能夠佔用計算元素樣式所需時間的50%以上。

* 減小必須進行樣式計算的元素的數量。本質上,直接對一些元素進行樣式更改,而不是使整個頁面無效。

優化佈局

瀏覽器的佈局從新計算可能很是繁重。 考慮如下優化:

  • 儘量減小布局的數量。當你更改樣式時,瀏覽器會檢查是否有任何更改須要從新計算佈局。對寬度、高度、左、頂等屬性的更改,以及一般與幾何相關的屬性的更改,都須要佈局。因此,儘可能避免改變它們。
  • 儘可能使用 flexbox 而不是老的佈局模型。它運行速度更快,可爲你的應用程序創造巨大的性能優點。
  • 避免強制同步佈局。須要記住的是,在 JavaScript 運行時,前一幀中的全部舊佈局值都是已知的,能夠查詢。若是你訪問 box.offsetHeight,那就不成問題了。可是,若是你在訪問 box 以前更改了它的樣式(例如,經過動態地向元素添加一些 CSS 類),瀏覽器必須先應用樣式更改並執行佈局過程,這是很是耗時和耗費資源的,因此儘量避免。

優化繪圖

這一般是全部任務中運行時間最長的,所以儘量避免這種狀況很是重要。 如下是咱們能夠作的事情:

  • 除了變換(transform)和透明度以外,改變其餘任何屬性都會觸發從新繪圖,請謹慎使用。
  • 若是觸發了佈局,那也會觸發繪圖,由於更改佈局會致使元素的視覺效果也改變。
  • 經過圖層提高和動畫編排來減小重繪區域。

原文:

blog.sessionstack.com...

關於Fundebug

Fundebug專一於JavaScript、微信小程序、微信小遊戲、支付寶小程序、React Native、Node.js和Java線上應用實時BUG監控。 自從2016年雙十一正式上線,Fundebug累計處理了9億+錯誤事件,付費客戶有Google、360、金山軟件、百姓網等衆多品牌企業。歡迎你們免費試用

相關文章
相關標籤/搜索