【譯】理解Repaint和Reflow

最近,在研究爲啥React的虛擬dom那麼快的時候,我意識到咱們不太瞭解javascript的性能。因此我寫這篇文章以幫助提升對Repaint,Reflow,JavaScript性能的認識。javascript

Reapint & Reflow

在咱們深刻以前,咱們知道瀏覽器是怎麼工做的麼?

一圖勝千言。因此,咱們從較高層面來看下瀏覽器的工做原理!css

high-level view

hmm...「browser engine(瀏覽器引擎)」和「rendering enging(渲染引擎)」是啥?html

瀏覽器引擎的主要工做是把HTML文檔和網頁的其它資源轉換成用戶可交互可視化的界面。 除了「browser engine」,還有另外經常使用的兩個術語:「layout engine(佈局引擎)」 和 「rendering enging(渲染引擎)」。理論上,佈局和渲染處理的引擎能夠單獨分開。不過實際上,它倆彼此緊密耦合因此不太會分開來講。java

讓咱們瞭解一下瀏覽器是如何在屏幕上畫出用戶界面的

當你點擊或輸入某個url,瀏覽器會向該頁面發起一個http請求,而且相應的服務器返回HTML文檔。(固然中間還有不少細節會發生)node

Step by step processing

  • 瀏覽器解析出HTML源代碼並構建一棵DOM樹,這棵DOM樹就是HTML節點的數據層表現,在這棵樹裏每一個HTML標籤都有一個對應的節點,標籤之間的文本也會獲得一個text node(文本節點)。這課DOM樹的根節點就是documentElement<html>標籤)react

  • 瀏覽器解析CSS代碼。樣式信息級聯:基本(樣式)規則在用戶代理樣式表中(瀏覽器默認值),接着多是用戶樣式表,網頁做者的樣式表 - 外部的,導入的,內聯的(就是把樣式寫在HTML標籤的屬性裏)。算法

  • 接下來是有趣的部分 - 構建渲染樹。渲染樹有點像DOM樹,可是不徹底是。渲染樹知道樣式,例如你用display:none來隱藏一個div的時候,它將不會在渲染樹中表示。其它看不見的元素也同樣,好比head及在它裏面的全部內容。另外一方面,渲染樹中可能存在用多個節點來表示(一個)DOM元素 - 好比文本節點,例如<p>節點裏每一行都須要一個渲染節點。渲染樹裏的一個節點被叫作box盒子模型)。每一個(渲染)節點都一個css盒子屬性 - width, height, border, margin,,等。api

  • 渲染樹創建好之後,瀏覽器就能把渲染樹節點畫到屏幕上。瀏覽器

這裏有個短視頻,瀏覽器是若是在屏幕上畫節點的。 視頻-畫的動態效果緩存

看不了的同窗,我這裏放一張靜態圖,感覺一下:

render圖

(視頻裏的過程)咱們可能根本就感受不到,發生在幾分之一秒內。

仔細看。

瀏覽器是如何佈局,如何檢測根節點,兄弟節點以及孩子節點,以及相應地從新排列他們的佈局。

讓咱們舉個例子

<html>
<head>
  <title>Repaint And Reflow</title>
</head>
<body>
    
  <p>
    <strong>How's The Josh?</strong>
    <strong><b> High Sir...</b></strong>
  </p>
  
  <div style="display: none">
    Nothing to display
  </div>
  
  <div><img src="..." /></div>
  ...
 
</body>
</html>
複製代碼

DOM樹裏基本每一個標籤都有一個節點對應,節點之間的每一個文本都有一個文本節點(這裏簡單起見,讓咱們忽略一下,其實一個空白(好比換行)也是一個文本節點)。

documentElement (html)
    head
        title
    body
        p
            strong
                [text node]
        p
            strong
                b
                    [text node]    		
        div 
            [text node]
		
        div
            img
		
        ...
複製代碼

而渲染樹是DOM樹的可視部分。不過他會少一點東西-head和hidden的div,不過也有額外複數行的文本節點。

root (RenderView)
    body
        p
            line 1
	    line 2
	    line 3
	    ...
	    
	div
	    img
	    
	...
複製代碼

渲染樹的根節點包含了全部元素的。你能夠認爲(這個根節點)就是瀏覽器裏面的那部分。WebKit把這個根節點稱做RenderView並把它與css裏的初始包含塊對應起來,也就是頁面的頂部(0,0)到(window.innerWidth, window.innerHeight)的可視區域。

要弄清楚哪些東西須要顯示在屏幕上,這個涉及到渲染樹的遞歸遍歷。

Repaint(重繪) and Reflow(迴流)

一般(頁面)都須要至少一次layout(迴流)和一次重繪(除非,你的頁面是空的:))。以後,改變渲染樹都會致使如下一種或兩種事情發生:

  1. 須要從新驗證渲染樹(部分或整個)以及從新計算節點尺寸。這就是迴流。注意必定會有一次迴流發生-頁面的初始佈局
  2. 頁面的部分須要更新,一個節點的幾何屬性發生變化,又或是樣式的變化(好比更改了background color),這個更新就叫作重繪。

重繪 和 迴流 消耗比較大,他們會下降用戶體驗以及卡UI。

Repaint(重繪)

顧名思義,重繪只不過是屏幕上從新繪製元素,由於元素更改的外觀會影響元素的可見性,但不會影響佈局。 好比下面幾個將會觸發重繪:

  1. 更改元素的可見性(visibility,opacity應該也算 )
  2. 更改元素的邊框
  3. 更改元素的背景

Reflow(迴流)

迴流是從新計算文檔中元素的位置和幾何形狀,以便從新顯示文檔的部分或所有。由於迴流會阻止用戶操做,因此開發者有必要知道怎樣優化迴流時間,瞭解各類文檔屬性(DOM深度,CSS效率,不一樣類型的樣式更改)對迴流時間的影響。有時候迴流單個元素可能會致使它的父元素們以及它其後的全部元素的迴流。

重繪與迴流no-no篇

虛擬DOM和真實DOM

每次DOM有改變,瀏覽器須要從新計算CSS,迴流及重繪頁面。這就是爲啥真實DOM比較耗時。

爲了最小化這個耗時,Ember 使用了 key/value 觀察者技術,Angular使用了髒檢測。用這種技術,就可以只更新變化了的dom節點(在Angular裏被標記爲髒的節點)。

不過,現代瀏覽器也變得聰明瞭,嘗試縮短重繪屏幕所需的時間。最大的變化就是可以重繪批處理DOM的更改。

React虛擬dom背後的理念就是減小和緩存dom變化

爲啥React的虛擬Dom很快?

React沒有作什麼新的事情,只是在策略上有動做。它把真實DOM存一份副本到內存裏。當你修改dom了,他先把(這個修改)應用到內存裏的DOM,而後使用它的對比算法,找出哪一個是真的有變化。

最後,它(react)批量處理這些變化而且一次性應用到真實的DOM上。因此,最小化了迴流和重繪。

原文

相關文章
相關標籤/搜索