渲染引擎經過經過網絡請求接收渲染內容javascript
渲染引擎的第一步是解析html文檔並將解析的元素轉換爲dom樹中的實際dom節點。
![]()
當瀏覽器解析dom的時候,遇到link標籤,引用外部的css樣式表,引擎會將css抽象成cssom
![]()
HTML中的可視指令與來自cssom樹的樣式數據結合使用來建立渲染樹。
![]()
爲了構建渲染樹,瀏覽器大體以下:
它包括幾何信息,如寬度,高度和位置css
當渲染器被建立並添加到樹中時,它沒有位置和大小。計算這些值稱爲佈局。html使用基於流的佈局模型,這意味着大多數時候它能夠一次性計算幾何。座標系相對於根渲染器。使用頂部和左側座標。html
佈局是一個遞歸過程,從根元素開始,也就是html,每一個渲染器都會去計算他本身的位置和大小html5
在這個階段,遍歷渲染器樹,調用渲染器的paint()方法在屏幕上顯示內容。
渲染分爲全局渲染和增量渲染java
當解析器到達script標記時,腳本將被當即解析並執行。
文檔的解析將暫停,直到腳本執行完畢。
這意味着該過程是同步的
這也是爲何把script標籤放在body結束以前web
html5添加了一個選項,將腳本標記爲異步,以便它能夠被其餘線程解析和執行。json
repaint重繪:瀏覽器
reflow迴流:緩存
減小reflow和repaint網絡
javascript
CSS
// 設置單個屬性 elt.style.color = "blue"; // 在單個語句中設置多個樣式 elt.style.cssText = "color: blue; border: 1px solid black"; // 在單個語句中設置多個樣式 elt.setAttribute("style", "color:red; border: 1px solid blue;");
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