性能優化中,減小重繪重排應該是一種很好的優化方式,咱們具體看一下什麼狀況下會形成重繪重排,爲何減小重繪重排能夠作到優化,怎麼樣減小重繪重排。css
咱們先看看當瀏覽器拿到服務端返回的資源時,是如何渲染的。html
首先瀏覽器會進行文件解析,主要解析三個東西:jquery
解析完成以後api
佈局完成以後,就要進行繪製了,將各層發給 GPU,GPU 將各層合成,顯示在屏幕上,即 composite。瀏覽器
當咱們開始繪製的時候,若是使用 js 操做了 dom 元素,或者改變了 css 屬性,就可能會形成重繪(repaint)和重排(reflow)。性能優化
repaint:屏幕的一部分進行了重畫,好比某個 css 中改變背景色,元素尺寸沒有變。 reflow:任何一個元素的尺寸發生了變化,須要從新驗證並計算 render tree,就會形成重排。app
在 PC 時代,咱們用 jquery 進行獲取元素,改變元素的尺寸,及時發生重排,咱們也很難感知到,可是當移動時代到來以後,若是頻繁發生重排,那手機就會受不了了。dom
尤爲是在執行下面操做時,成本會很高:svg
若是發生上述的行爲基本都會形成重繪和重排。工具
當發生重排時,必定會發生重繪,可是發生重繪不必定會發生重排。
瀏覽器中每一個元素節點都有 reflow 方法,當一個元素髮生 reflow 時,他的子節點都會發生 reflow。
舉幾個例子來講明一下形成重繪重排的狀況:
var bodyStyle = document.body.style; // cache
bodyStyle.padding = '20px'; // reflow, repaint
bodyStyle.border = '10px solid red'; // 再一次的 reflow 和 repaint
bodyStyle.color = 'blue'; // repaint
bodyStyle.backgroundColor = '#fad'; // repaint
bodyStyle.fontSize = '2em'; // reflow, repaint
// new DOM element - reflow, repaint
document.body.appendChild(document.createTextNode('children!'));
複製代碼
前面說了瀏覽器的渲染機制,多一次重繪就須要瀏覽器從新進行一次繪製,及時 GPU 處理會比較快,可是也是吃不消的,更別說重排了,重排一個 dom,會從新生成 render Tree,而後從新繪製。
其實瀏覽器很聰明,不可能每次修改樣式就 reflow 或者 repaint 一次,通常來講,瀏覽器會積累一批操做,而後作一次 reflow。
可是也有些例外狀況,好比 resize 窗口,改變窗口字體,瀏覽器會當即進行 reflow。
雖然瀏覽器會這麼作,可是咱們也應該減小重繪重排的次數,在開發階段就爲瀏覽器進行特殊的關愛,畢竟是天天陪伴咱們的小夥伴。
下面總結了一些針對 reflow 和 repaint 的最佳實踐:
當每次佈局完成以後,就會發生 composite 過程,瀏覽器都把重繪後的圖像發給 GPU 去合成並顯示。
在上面最佳實踐中最後提到了動畫,動畫實際上是比較耗費性能的,由於動畫的每一幀都會發給 GPU 去合成,重繪重排會發生在動畫的每一幀。
咱們在寫動畫的時候,能夠經過 js 寫,也能夠經過 css 寫。兩種方式在寫動畫時,過程也是不同的。
因此不難看出,耗費性能最少並能並最流暢的動畫是隻觸發合成。
爲了僅發生 composite,咱們作動畫的 css property 必須知足如下三個條件:
知足以上以上條件的 css property 只有 transform 和 opacity。
這樣的話,因爲沒有重排和重繪,只有合成,那麼瀏覽器在動畫執行以前就知道動畫如何開始和結束。
而且有兩個優點:
事實上影響動畫流暢性的因素不止重排重繪,還有 CPU 內存。
css 動畫有一個重要的特性,它是徹底工做在 GPU 上。由於你聲明瞭一個動畫如何開始和如何結束,瀏覽器會在動畫開始前準備好全部須要的指令;並把它們發送給 GPU。
而若是使用 js 動畫,瀏覽器必須計算每一幀的狀態;爲了保證平滑的動畫,咱們必須在瀏覽器主線程計算新狀態;把它們發送給 GPU 至少 60 次每秒。
除了計算和發送數據比 css 動畫要慢,主線程的負載也會影響動畫; 當主線程的計算任務過多時,會形成動畫的延遲、卡頓。
因此最佳實踐中最後一條就提到了,在寫動畫時,儘可能寫 css 動畫,而且儘可能用 transform 和 opacity。
谷歌瀏覽器檢測重繪工具:右上角...,more tools,rendering。
勾選了 paint flashing 時,在刷新頁面以後,就會發現有有綠色的背景,有綠色的背景就表明着重排。
還能夠勾選 FPS meter,能夠查看渲染頁面時候 GPU 的使用率。
方便發現本身在開發過程當中,哪些操做形成了重繪重排,儘可能減小修改次數,優化性能。