前言
瀏覽器下載完頁面中的所有內(nèi)容:HTML、JavaScript、CSS、圖片——之后會(huì)解析并生成兩個(gè)內(nèi)部數(shù)據(jù)結(jié)構(gòu):
DOM樹:表示頁面結(jié)構(gòu) 渲染樹:表示DOM節(jié)點(diǎn)如何顯示DOM樹中的每一個(gè)需要顯示的節(jié)點(diǎn)在渲染樹中至少存在一個(gè)對(duì)應(yīng)的節(jié)點(diǎn)(隱藏的DOM元素在渲染樹中沒有對(duì)應(yīng)的節(jié)點(diǎn))。渲染樹中的節(jié)點(diǎn)被稱為“幀”或者“盒子”,理解頁面元素為一個(gè)具有填充(padding)、邊距(margin)、邊框(border)和位置(position)的盒子。一旦DOM樹和渲染樹構(gòu)建完成,瀏覽器就開始顯示(繪制 paint)頁面元素
當(dāng)DOM的改變影響了元素幾何屬性(例如寬和高)——瀏覽器就需要重新計(jì)算元素的幾何特性,同樣其他元素的幾何屬性和位置也會(huì)因此受到影響。瀏覽器會(huì)使渲染樹中受到影響的部分失效,并重新構(gòu)造渲染樹。這個(gè)過程稱為重排(reflow)。完成重排后,瀏覽器會(huì)重新繪制受到影響的部分到屏幕中,該過程稱為重繪(repaint)
重繪和重排操作都是代價(jià)昂貴的操作,它們會(huì)導(dǎo)致web應(yīng)用程序的UI反應(yīng)遲鈍,所以應(yīng)該盡可能減少這類過程的發(fā)生。
引起重排的原因
渲染樹變化的排隊(duì)與刷新
由于每次重排都會(huì)產(chǎn)生計(jì)算消耗,大多數(shù)瀏覽器通過隊(duì)列化修改和批量執(zhí)行來優(yōu)化重排過程(將多個(gè)重排過程合并成一次)。然而,某些操作會(huì)強(qiáng)制刷新隊(duì)列并要求隊(duì)列中的重排立即執(zhí)行(這樣會(huì)使瀏覽器的優(yōu)化策略失效)。
獲取布局信息的操作會(huì)導(dǎo)致強(qiáng)制刷新隊(duì)列,使得瀏覽器不得不執(zhí)行渲染隊(duì)列中的“待處理變化”并觸發(fā)重排以返回正確的值 offsetTop,offsetLeft,offsetWidth,offsetHeight scrollTop,scrollLeft,scrollWidth,scrollHeight clientTop,clientLeft,clientWidth,clientHeight getComputedStyle() 優(yōu)化方法:盡量不要在布局信息改變時(shí)查詢它,可以在布局信息改變完畢之后再去查詢最小化重繪和重排
重繪和重排的代價(jià)非常昂貴,因此一個(gè)好的提高程序響應(yīng)速度的策略就是減少此類操作的發(fā)生。為了減少發(fā)生次數(shù),應(yīng)該合并多次對(duì)DOM和樣式的修改,然后一次處理掉。
合并多次對(duì)樣式的修改
var el = document.getElementById('myDiv')el.style.borderLeft = '1px'el.style.borderRight = '2px'el.style.padding = '5px'上面的例子中,存在兩個(gè)問題:
每個(gè)樣式屬性的改變都會(huì)影響元素的集合結(jié)構(gòu),最糟糕的情況下,會(huì)導(dǎo)致瀏覽器觸發(fā)三次重排(大部分現(xiàn)代瀏覽器都為此做了優(yōu)化,只會(huì)觸發(fā)一次重排) 上面的代碼訪問了4次DOM新聞熱點(diǎn)
疑難解答
圖片精選