前端優化,瞭解瀏覽器重排與重繪
2018年3月15日
當DOM變化影響了元素的幾何屬性(寬、高改變等等)
瀏覽器此時需要重新計算元素幾何屬性
並且頁面中其他元素的幾何屬性可能會受影響
這樣渲染樹就發生了改變,也就是重新構造RenderTree渲染樹
這個過程叫做重排(reflow)
如果DOM變化僅僅影響的了背景色等等非幾何屬性
此時就發生了重繪(repaint)而不是重排
因為佈局沒有發生改變
頁面發生重繪和重排,都會影響效能(重繪還好一些),儘量避免或減少重排
觸發重排
頁面佈局和元素幾何屬性的改變就會導致重排
下列情況會發生重排
- 頁面初始渲染
- 新增/刪除可見DOM元素
- 改變元素位置
- 改變元素尺寸(寬、高、內外邊距、邊框等)
- 改變元素內容(文字或圖片等)
- 改變視窗尺寸
不同的條件下發生重排的範圍及程度會不同
某些情況甚至會重排整個頁面,比如滑動滾動條
瀏覽器的優化:渲染佇列
- div.style.left = `10px`;
- div.style.top = `10px`;
- div.style.width = `20px`;
- div.style.height = `20px`;
如上,修改了元素的left、top、width、height屬性
滿足我們發生重排的條件
理論上會發生4次重排
但是實際上只會發生1次重排
這是因為我們現代的瀏覽器都有渲染佇列的機制
當我改變了元素的一個樣式會導致瀏覽器發生重排或重繪時
它會進入一個渲染佇列
然後瀏覽器繼續往下看,如果下面還有樣式修改
那麼同樣入隊
直到下面沒有樣式修改
瀏覽器會按照渲染佇列批量執行來優化重排過程,一併修改樣式
這樣就把本該4次的重排優化為1次
div.style.left = `10px`;
console.log(div.offsetLeft);
div.style.top = `10px`;
console.log(div.offsetTop);
div.style.width = `20px`;
console.log(div.offsetWidth);
div.style.height = `20px`;
console.log(div.offsetHeight);
如上,發生4次重排
offsetLeft/Top/Width/Height 會強制重新整理佇列要求樣式修改任務立刻執行
這麼做是有道理的
畢竟瀏覽器不確定在接下來的程式碼中你是否還會修改同樣的樣式
為了保證獲得正確的值,它不得不立刻執行渲染佇列觸發重排
以下屬性或方法會重新整理渲染佇列
- offsetTop、offsetLeft、offsetWidth、offsetHeight
- clientTop、clientLeft、clientWidth、clientHeight
- scrollTop、scrollLeft、scrollWidth、scrollHeight
- getComputedStyle()(IE中currentStyle)
我們在修改樣式過程中,要儘量避免使用上面的屬性
重繪與重排的效能優化
分離讀寫操作
瞭解了原理我們就可以對上面的程式碼進行優化
- div.style.left = `10px`;
- div.style.top = `10px`;
- div.style.width = `20px`;
- div.style.height = `20px`;
- console.log(div.offsetLeft);
- console.log(div.offsetTop);
- console.log(div.offsetWidth);
- console.log(div.offsetHeight);
僅僅發生1次重排了,原因相信大家已經很清晰了
把所有的讀操作移到所有寫操作之後
樣式集中改變
還是我們最初修改樣式的程式碼
div.style.left = `10px`;
div.style.top = `10px`;
div.style.width = `20px`;
div.style.height = `20px`;
如上,雖然現代瀏覽器有渲染佇列的優化機制
但是古董瀏覽器效率仍然低下,觸發了4次重排
即便這樣,我們仍然可以做出優化
我們需要cssText屬性合併所有樣式改變
div.style.cssText = `left:10px;top:10px;width:20px;height:20px;`;
如上,只需要修改DOM一次一併處理
僅僅觸發了1次重排
而且只用了一行程式碼,看起來相對乾淨一些
注意,cssText會覆蓋已有的行間樣式
如果想保留原有行間樣式,如下
div.style.cssText += `;left:10px;`;
除了cssText以外,我們還可以通過修改class類名來進行樣式修改,如下
div.className = `new-class`;
這種辦法可維護性好,還可以幫助我們免除顯示性程式碼
有很小的效能影響,改變class需要檢查級聯樣式,但是符合BEM標準可以更好的解耦,增加可維護性,建議這樣寫
div.className = `js-class`;
快取佈局資訊
我覺得快取真是萬金油,哪種效能優化都少不了它
div.style.left = div.offsetLeft + 1 + `px`;
div.style.top = div.offsetTop + 1 + `px`;
如上,這種讀操作完就執行寫操作造成了2次重排
快取可以進行優化
var curLeft = div.offsetLeft;
var curTop = div.offsetTop;
div.style.left = curLeft + 1 + `px`;
div.style.top = curTop + 1 + `px`;
如上,這也相當於是分離讀寫操作了
優化為1次重排
元素批量修改
現在我們想要向ul中迴圈新增大量li
(如果ul還不存在,最好的辦法是先迴圈新增li到ul,然後再把ul新增到文件,1次重排)
var ul = document.getElementById(`demo`);
for(var i = 0; i < 1e5; i++){
var li = document.createElement(`li`);
var text = document.createTextNode(i);
li.appendChild(text); ul.appendChild(li);
}
我可以做出下面的優化
var ul = document.getElementById(`demo`);
ul.style.display = `none`;
for(var i = 0; i < 1e5; i++){
var li = document.createElement(`li`);
var text = document.createTextNode(i);
li.appendChild(text); ul.appendChild(li);
}
ul.style.display = `block`;
var ul = document.getElementById(`demo`);
var frg = document.createDocumentFragment();
for(var i = 0; i < 1e5; i++){
var li = document.createElement(`li`);
var text = document.createTextNode(i);
li.appendChild(text); frg.appendChild(li);
}
ul.appendChild(frg);
var ul = document.getElementById(`demo`);
var clone = ul.cloneNode(true);
for(var i = 0; i < 1e5; i++){
var li = document.createElement(`li`);
var text = document.createTextNode(i);
li.appendChild(text); clone.appendChild(li);
}
ul.parentNode.replaceChild(clone,ul);
上面的方法減少重繪和重排的原理很簡單
- 元素脫離文件
- 改變樣式
- 元素迴歸文件
而改變元素就分別使用了
隱藏元素
文件碎片
克隆元素
相關文章
- 前端效能優化:細說瀏覽器渲染的重排與重繪前端優化瀏覽器
- 【高效能JS】重繪、重排與瀏覽器優化方法JS瀏覽器優化
- 瀏覽器重繪(repaint)重排(reflow)與優化[瀏覽器機制]瀏覽器AI優化
- 瀏覽器渲染原理(效能優化之如何減少重排和重繪)瀏覽器優化
- 瀏覽器的迴流與重繪 (Reflow & Repaint)瀏覽器AI
- 瀏覽器迴流和重繪瀏覽器
- 前端效能優化 —— 移動端瀏覽器優化策略前端優化瀏覽器
- 前端效能優化(一)——瀏覽器工作原理前端優化瀏覽器
- 前端效能優化 之 瀏覽器快取前端優化瀏覽器快取
- 重排和重繪
- 前端效能優化(二)——瀏覽器快取機制前端優化瀏覽器快取
- 前端優化:瀏覽器快取技術介紹前端優化瀏覽器快取
- 瀏覽器層合成與頁面效能優化瀏覽器優化
- 前端基於瀏覽器儲存的AJAX效能優化前端瀏覽器優化
- 你應該要知道的重繪與重排
- 瞭解新版“武漢鏈”瀏覽器瀏覽器
- 瀏覽器快取你瞭解麼?瀏覽器快取
- CSS新特性contain,控制頁面的重繪與重排CSSAI
- 深入瞭解瀏覽器儲存:對比Cookie、LocalStorage、sessionStorage與IndexedDB瀏覽器CookieSessionIndex
- 前端面試瀏覽器系列:瀏覽器快取前端面試瀏覽器快取
- 高效能JavaScript 重排與重繪 讀書筆記JavaScript筆記
- 精讀《深入瞭解現代瀏覽器一》瀏覽器
- 精讀《深入瞭解現代瀏覽器二》瀏覽器
- 精讀《深入瞭解現代瀏覽器四》瀏覽器
- 精讀《深入瞭解現代瀏覽器三》瀏覽器
- 前端面試:Http協議與瀏覽器前端面試HTTP協議瀏覽器
- 淺談瀏覽器重排(Relayout/Reflow)瀏覽器
- 瀏覽器渲染流水線解析與網頁動畫效能優化瀏覽器網頁動畫優化
- [譯]從內部瞭解現代瀏覽器(2)瀏覽器
- [譯]從內部瞭解現代瀏覽器(3)瀏覽器
- [譯]從內部瞭解現代瀏覽器(1)瀏覽器
- 關於迴流與重繪優化的探索優化
- 瀏覽器工作原理及web 效能優化(上)瀏覽器Web優化
- 深入瞭解 TiDB SQL 優化器TiDBSQL優化
- 瀏覽器帶你學前端瀏覽器前端
- 迴流、重繪及其優化優化
- 一張圖瞭解瀏覽器渲染頁面的過程瀏覽器
- 重學瀏覽器(1)-多程式多執行緒的瀏覽器瀏覽器執行緒