摘要:回流重繪及其優化渲染過程渲染引擎通過通過網絡請求接收渲染內容解析抽象抽象出布局繪畫抽象渲染引擎的第一步是解析文檔并將解析的元素轉換為樹中的實際節點。
回流、重繪及其優化 渲染過程
渲染引擎通過通過網絡請求接收渲染內容
解析HTML抽象DOM tree
抽象出Render tree
布局(layout)render tree
繪畫render tree
抽象DOM tree渲染引擎的第一步是解析html文檔并將解析的元素轉換為dom樹中的實際dom節點。抽象CSSOM tree
當瀏覽器解析dom的時候,遇到link標簽,引用外部的css樣式表,引擎會將css抽象成cssom構建渲染樹
HTML中的可視指令與來自cssom樹的樣式數據結合使用來創建渲染樹。
為了構建渲染樹,瀏覽器大致如下:
從dom樹的根開始,遍歷每個可見節點。某些節點不可見(例如,腳本標記,元標記等),并且由于它們未反映在呈現的輸出中而被省略。display:none 也會使節點省略
對于每個可見節點,瀏覽器找到適當的匹配cssom規則并應用它們
它會發布帶有內容和計算樣式的可見節點
每個渲染器代表一個矩形區域,通常對應于一個節點的CSS框。
它包括幾何信息,如寬度,高度和位置
渲染樹的布局當渲染器被創建并添加到樹中時,它沒有位置和大小。計算這些值稱為布局。繪制渲染樹html使用基于流的布局模型,這意味著大多數時候它可以一次性計算幾何。坐標系相對于根渲染器。使用頂部和左側坐標。
布局是一個遞歸過程,從根元素開始,也就是html,每個渲染器都會去計算他自己的位置和大小
在這個階段,遍歷渲染器樹,調用渲染器的paint()方法在屏幕上顯示內容。
渲染分為全局渲染和增量渲染
處理腳本和樣式表的順序當解析器到達script標記時,腳本將被立即解析并執行。
文檔的解析將暫停,直到腳本執行完畢。
這意味著該過程是同步的
這也是為什么把script標簽放在body結束之前
html5添加了一個選項,將腳本標記為異步,以便它可以被其他線程解析和執行。
回流和重繪(reflow和repaint)回流: 意味著元素的內容、結構、位置或尺寸發生了變化,需要重新計算樣式和渲染樹;
重繪:意味著元素發生的改變只影響了節點的一些樣式(背景色,邊框顏色,文字顏色等),只需要應用新樣式繪制這個元素就可以了;
何時觸發回流和重繪
repaint重繪:
reflow回流必定引起repaint重繪,重繪可以多帶帶觸發
背景色、顏色、字體改變(注意:字體大小發生變化時,會觸發回流)
reflow回流:
頁面第一次渲染(初始化)
DOM樹變化(如:增刪節點)
Render樹變化(如:padding改變)
瀏覽器窗口resize
當你查詢布局信息,包括offsetLeft、offsetTop、offsetWidth、offsetHeight、 scrollTop/Left/Width/Height、clientTop/Left/Width/Height、調用了getComputedStyle()或者IE的currentStyle時,瀏覽器為了返回最新值,會觸發回流。
優化渲染性能,減少回流和重繪減少reflow和repaint
盡量避免改變布局屬性。如width, height, left, top。
除了transforms 或者 opacity屬性都會引起重繪,做動畫的時候要注意,盡量使用這兩個屬性;
使用Flexbox。
避免多次讀取部分布局屬性(同上)
將復雜的節點元素脫離文檔流,降低回流成本
javascript
避免使用setTimeout setInterval 來更新視圖,這會在render之后提交修改需求
在micro-tasks中修改dom。這會在render之前提交修改需求
把script標簽放在body結束之前,或者使用異步script(defer, async)
把計算量大的js放在workers執行,例如解析一個大的json文件
CSS
減少選擇器的復雜性。
避免逐個修改節點樣式,盡量一次性修改,減少style修改所影響元素的數量,使用cssText來替代要多次修改的style屬性
// 設置單個屬性 elt.style.color = "blue"; // 在單個語句中設置多個樣式 elt.style.cssText = "color: blue; border: 1px solid black"; // 在單個語句中設置多個樣式 elt.setAttribute("style", "color:red; border: 1px solid blue;");
通過改變類名來修改樣式
DOM
使元素脫離文檔流
對其應用多重修改
把元素帶回文檔中
這個過程會觸發兩次回流,第一步和第三步。把會觸發多次回流的步驟放在第二步
三種基本方法:
display:none,然后修改樣式,然后在恢復
使用文檔片段(document fragment)在當前dom樹之外構建一個子樹,再把他拷貝回文檔。
var fragment = document.createDocumentFragment() ... 在這里進行dom操作,可以減少回流和重繪的次數 document.getElementById("#app").appendChild(fragment)
將原始元素拷貝到一個脫離文檔的節點中,修改副本,完成后替換原始元素
var old = document.getElementById("#app") var clone = old.cloneNode(true) ... 在這里進行dom操作,可以減少回流和重繪的次數 old.parentNode.replaceChild(clone, old)
緩存布局信息
前面提到在查詢布局信息(offsetLeft...)的時候也會引起回流,我們在使用的時候可以把布局信息緩存起來,減少回流次數
這里貼上<<高性能javascript>>中的例子:把myElement元素沿對角線移動,每次移動一個像素,從100100的位置開始,到500500的位置結束。在timeout循環體中你可以使用下面的方法
// 低效的 myElement.style.left = 1 + myElement.offsetLeft + "px" myElement.style.top = 1 + myElement.offsetTop + "px" if (myElement.offsetTop >= 500) { stopAnimation(); }
// 優化 // 在循環外層獲取初始值 var current = myElement.offsetLeft . . . // 直接使用current變量,不再查詢偏移量 current++ myElement.style.left = current + "px" myElement.style.top = current + "px" if (current >= 500) { stopAnimation(); }
使元素進行動畫效果的時候脫離文檔流
在元素發生動畫效果的時候,會引起底部元素的回流,這個影響可能很大,也可能很小,取決于元素在文檔流的位置
動畫元素使用絕對定位,使其脫離文檔流
這里再進行旋轉,跳躍,都不會影響到整個頁面的回流
在動畫結束時恢復定位,從而只會下移一次文檔的其他元素。
參考DOM操作成本到底高在哪兒
參考高性能javascript
參考How JavaScript works: the rendering engine and tips to optimize its performance
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/94407.html
摘要:何時發生有大量的用戶行為以及潛在的改變會觸發回流。這樣就會讓多次的回流重繪變成一次回流重繪。因為上的操作不會引發回流和重繪。參考文章回流與重繪性能讓變慢參考文章瀏覽器的重繪與重排 推薦了解的知識:基本的HTML,基本的JavaScript,以及一些css工作原理方面的知識 瀏覽器的渲染原理 css的加載和解析不會阻塞html文檔的解析 css的解析會阻塞js的執行,必須等到CSSOM...
閱讀 2188·2021-11-15 11:38
閱讀 1151·2021-09-06 15:02
閱讀 3379·2021-08-27 13:12
閱讀 1353·2019-08-30 14:20
閱讀 2389·2019-08-29 15:08
閱讀 636·2019-08-29 14:08
閱讀 1722·2019-08-29 13:43
閱讀 1464·2019-08-26 12:11