網(wǎng)頁性能管理:重繪和重排

網(wǎng)頁生成的過程

要理解網(wǎng)頁性能為什么不好,就要了解網(wǎng)頁是怎么生成的悉患。

網(wǎng)頁的生成過程肩钠,大致可以分成五步:
1.HTML代碼轉(zhuǎn)化成DOM
2.CSS代碼轉(zhuǎn)化成CSSOMCSS Object Model)兽间。
3.結(jié)合DOMCSSOM历葛,生成一棵渲染樹(包含每個(gè)節(jié)點(diǎn)的視覺信息)。
4.生成布局(layout)嘀略,即將所有渲染樹的所有節(jié)點(diǎn)進(jìn)行平面合成恤溶。
5.將布局繪制(paint)在屏幕上。

"生成布局"(flow)和"繪制"(paint)這兩步帜羊,合稱為"渲染"(render)咒程。

重排和重繪

網(wǎng)頁生成的時(shí)候,至少會(huì)渲染一次讼育。用戶訪問的過程中帐姻,還會(huì)不斷重新渲染稠集。

重新渲染,就需要重新生成布局和重新繪制饥瓷。前者叫做重排(reflow)剥纷,后者叫做重繪(repaint)。

需要注意的是呢铆,重繪不一定需要重排晦鞋,重排必然導(dǎo)致重繪

對(duì)于性能的影響

提高網(wǎng)頁性能棺克,就是要降低"重排"和"重繪"的頻率和成本悠垛,盡量少觸發(fā)重新渲染。

DOM變動(dòng)和樣式變動(dòng)逆航,都會(huì)觸發(fā)重新渲染鼎文。但是,瀏覽器已經(jīng)很智能了因俐,會(huì)盡量把所有的變動(dòng)集中在一起拇惋,排成一個(gè)隊(duì)列,然后一次性執(zhí)行抹剩,盡量避免多次重新渲染撑帖。

div.style.color = 'blue';
div.style.marginTop = '30px';

上面代碼中,div元素有兩個(gè)樣式變動(dòng)澳眷,但是瀏覽器只會(huì)觸發(fā)一次重排和重繪胡嘿。

如果寫得不好,就會(huì)觸發(fā)兩次重排和重繪钳踊。

div.style.color = 'blue';
var margin = parseInt(div.style.marginTop);
div.style.marginTop = (margin + 10) + 'px';

上面代碼對(duì)div元素設(shè)置背景色以后衷敌,第二行要求瀏覽器給出該元素的位置,所以瀏覽器不得不立即重排拓瞪。

一般來說缴罗,樣式的寫操作之后,如果有下面這些屬性的讀操作祭埂,都會(huì)引發(fā)瀏覽器立即重新渲染面氓。

offsetTop/offsetLeft/offsetWidth/offsetHeight
scrollTop/scrollLeft/scrollWidth/scrollHeight
clientTop/clientLeft/clientWidth/clientHeight
getComputedStyle()

所以,從性能角度考慮蛆橡,盡量不要把讀操作和寫操作舌界,放在一個(gè)語句里面。

// bad
div.style.left = div.offsetLeft + 10 + "px";
div.style.top = div.offsetTop + 10 + "px";

// good
var left = div.offsetLeft;
var top  = div.offsetTop;
div.style.left = left + 10 + "px";
div.style.top = top + 10 + "px";

一般的規(guī)則是:

  • 樣式表越簡(jiǎn)單泰演,重排和重繪就越快呻拌。
  • 重排和重繪的DOM元素層級(jí)越高,成本就越高睦焕。
  • table元素的重排和重繪成本柏锄,要高于div元素酿箭。

重排何時(shí)發(fā)生

  • 添加或者刪除可見的DOM元素。
  • 元素位置改變趾娃。
  • 元素尺寸改變缭嫡。
  • 元素內(nèi)容改變(例如:一個(gè)文本被另一個(gè)不同尺寸的圖片替代)。
  • 頁面渲染初始化(這個(gè)無法避免)抬闷。
  • 瀏覽器窗口尺寸改變妇蛀。

最小化重繪和重排

  • DOM的多個(gè)讀操作(或多個(gè)寫操作),應(yīng)該放在一起笤成。不要兩個(gè)讀操作之間评架,加入一個(gè)寫操作。

  • 如果某個(gè)樣式是通過重排得到的炕泳,那么最好緩存結(jié)果纵诞。避免下一次用到的時(shí)候,瀏覽器又要重排培遵。

  • 不要一條條地改變樣式浙芙,而要通過改變class,或者csstext屬性籽腕,一次性地改變樣式嗡呼。

// bad
var left = 10;
var top = 10;
el.style.left = left + "px";
el.style.top  = top  + "px";

// good 
el.className += " theclassname";

// good
el.style.cssText += "; left: " + left + "px; top: " + top + "px;";
  • 盡量使用離線DOM,而不是真實(shí)的網(wǎng)面DOM皇耗,來改變?cè)貥邮侥洗啊1热纾僮?code>Document Fragment對(duì)象郎楼,完成后再把這個(gè)對(duì)象加入DOM万伤。再比如,使用 cloneNode()方法呜袁,在克隆的節(jié)點(diǎn)上進(jìn)行操作敌买,然后再用克隆的節(jié)點(diǎn)替換原始節(jié)點(diǎn)。
<ul id='fruit'>
    <li> apple </li> 
    <li> orange </li>
</ul>

如果代碼中要添加內(nèi)容為peach傅寡、watermelon兩個(gè)選項(xiàng)放妈,你會(huì)怎么做北救?

let lis = document.getElementById('fruit');
let li=document.createElement('li');
li.innerHTML='apple';
lis.appendChild(li);

let li = document.createElement('li');
li.innerHTML = 'watermelon';
lis.appendChild(li);

很容易想到如上代碼荐操,但是很顯然,重排了兩次珍策,怎么破托启?
前面我們說了,隱藏的元素不在渲染樹中攘宙,太棒了屯耸,我們可以先把idfruitul元素隱藏(display=none)拐迁,然后添加li元素,最后再顯示疗绣,但是實(shí)際操作中可能會(huì)出現(xiàn)閃動(dòng)线召,原因這也很容易理解。

這時(shí)多矮,fragment元素就有了用武之地了缓淹。

let fragment = document.createDocumentFragment();

let li = document.createElement('li');
li.innerHTML = 'apple';
fragment.appendChild(li);

let li = document.createElement('li');
li.innerHTML = 'watermelon';
fragment.appendChild(li);

document.getElementById('fruit').appendChild(fragment);

文檔片段是個(gè)輕量級(jí)的document對(duì)象,它的設(shè)計(jì)初衷就是為了完成這類任務(wù)——更新和移動(dòng)節(jié)點(diǎn)塔逃。文檔片段的一個(gè)便利的語法特性是當(dāng)你附加一個(gè)片斷到節(jié)點(diǎn)時(shí)讯壶,實(shí)際上被添加的是該片斷的子節(jié)點(diǎn),而不是片斷本身湾盗。只觸發(fā)了一次重排伏蚊,而且只訪問了一次實(shí)時(shí)的DOM

  • 先將元素設(shè)為display: none(需要1次重排和重繪)格粪,然后對(duì)這個(gè)節(jié)點(diǎn)進(jìn)行100次操作躏吊,最后再恢復(fù)顯示(需要1次重排和重繪)。這樣一來匀借,你就用兩次重新渲染颜阐,取代了可能高達(dá)100次的重新渲染。

  • position屬性為absolutefixed的元素吓肋,重排的開銷會(huì)比較小凳怨,因?yàn)椴挥每紤]它對(duì)其他元素的影響。

  • 只在必要的時(shí)候是鬼,才將元素的display屬性為可見肤舞,因?yàn)椴豢梢姷脑夭挥绊懼嘏藕椭乩L。另外均蜜,visibility : hidden的元素只對(duì)重繪有影響李剖,不影響重排。

  • 使用虛擬DOM的腳本庫囤耳,比如React等篙顺。

  • 使用window.requestAnimationFrame()window.requestIdleCallback()這兩個(gè)方法調(diào)節(jié)重新渲染.

參考文檔:
高性能JavaScript 重排與重繪
網(wǎng)頁性能管理詳解

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末充择,一起剝皮案震驚了整個(gè)濱河市德玫,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌椎麦,老刑警劉巖宰僧,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異观挎,居然都是意外死亡琴儿,警方通過查閱死者的電腦和手機(jī)段化,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來造成,“玉大人显熏,你說我怎么就攤上這事∩故海” “怎么了佃延?”我有些...
    開封第一講書人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)夷磕。 經(jīng)常有香客問我履肃,道長(zhǎng),這世上最難降的妖魔是什么坐桩? 我笑而不...
    開封第一講書人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任尺棋,我火速辦了婚禮,結(jié)果婚禮上绵跷,老公的妹妹穿的比我還像新娘膘螟。我一直安慰自己,他們只是感情好碾局,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開白布荆残。 她就那樣靜靜地躺著,像睡著了一般净当。 火紅的嫁衣襯著肌膚如雪内斯。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,185評(píng)論 1 284
  • 那天像啼,我揣著相機(jī)與錄音俘闯,去河邊找鬼。 笑死忽冻,一個(gè)胖子當(dāng)著我的面吹牛真朗,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播僧诚,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼遮婶,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了湖笨?” 一聲冷哼從身側(cè)響起旗扑,我...
    開封第一講書人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎赶么,沒想到半個(gè)月后肩豁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體脊串,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡辫呻,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年清钥,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片放闺。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡祟昭,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出怖侦,到底是詐尸還是另有隱情篡悟,我是刑警寧澤,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布匾寝,位于F島的核電站搬葬,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏艳悔。R本人自食惡果不足惜急凰,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望猜年。 院中可真熱鬧抡锈,春花似錦、人聲如沸钱反。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至撇簿,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間差购,已是汗流浹背补疑。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留歹撒,地道東北人莲组。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像暖夭,于是被迫代替她去往敵國(guó)和親锹杈。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容