瀏覽器的渲染流程--重排包蓝、重繪、合成

HTML呆奕、CSS养晋、JavaScript 數(shù)據(jù),經(jīng)過瀏覽器中間渲染模塊的處理梁钾,再加上重排绳泉、重繪合成的一個個環(huán)節(jié)姆泻,才最終輸出為屏幕上的像素視圖畫面零酪。本文就逐一介紹重排重繪拇勃、合成的基本概念四苇、觸發(fā)時機、影響范圍以及其優(yōu)化策略方咆。

重排月腋、重繪、合成

一瓣赂、瀏覽器渲染原理

一個完整的渲染流程一般都經(jīng)歷如下過程:

  1. HTML被HTML解析器解析成DOM Tree
  2. CSS則被CSS解析器解析成CSSOM Tree
  3. DOM TreeCSSOM Tree解析完成后榆骚,被附加到一起,形成渲染樹(Render Tree
  4. 布局煌集,根據(jù)渲染樹計算每個節(jié)點的幾何信息生成布局樹Layout Tree
  5. 對布局樹進行分層妓肢,并生成分層樹Layer Tree
  6. 為每個圖層生成繪制列表
  7. 渲染繪制(Paint)。根據(jù)計算好的繪制列表信息繪制整個頁面苫纤,并將其提交到合成線程
  8. 合成線程將圖層分成圖塊碉钠,并在光柵化線程池中將圖塊轉(zhuǎn)換成位圖,發(fā)送繪制圖塊命令 DrawQuad 給瀏覽器進程
  9. 瀏覽器進程根據(jù) DrawQuad 消息生成頁面卷拘,并顯示到顯示器上

二喊废、重排

定義: 當通過JS或css改變了元素的寬度、高度等栗弟,修改了元素的幾何位置屬性操禀,那么瀏覽器會觸發(fā)重新布局,解析之后的一系列子階段横腿,這個過程就叫重排颓屑。無疑斤寂, 重排需要更新完整的渲染流水線,所以開銷也是最大的揪惦。

觸發(fā)時機和影響范圍: DOM節(jié)點信息更改,觸發(fā)重排時遍搞,這個DOM更改程度會決定周邊DOM更改范圍。

全局范圍: 就是從根節(jié)點html開始對整個渲染樹進行重新布局器腋,例如當我們改變了窗口尺寸或方向或者是修改了根元素的尺寸或者字體大小等溪猿。

局部范圍: 對渲染樹的某部分或某一個渲染對象進行重新布局。

三纫塌、重繪

定義: 如果修改了元素的背景顏色诊县,并沒有引起幾何位置的變換,所以就直接進入了繪制階段措左,然后執(zhí)行之后的一系列子階段依痊,這個過程就叫重繪相較于重排操作怎披,重繪省去了布局和分層階段胸嘁,所以執(zhí)行效率會比重排操作要高一些。

觸發(fā)時機和影響范圍: 每一次的dom更改或者css幾何屬性更改凉逛,都會引起一次瀏覽器的重排/重繪過程性宏,而如果是css的非幾何屬性更改,則只會引起重繪過程状飞。

四毫胜、合成

定義: 合成是一種將頁面的各個部分分離成層(Layer Tree),分別將它們柵格化诬辈,然后在稱為“合成線程”的中組合為頁面的技術(shù)指蚁。

觸發(fā)時機和影響范圍: 在GUI渲染線程后執(zhí)行,將GUI渲染線程生成的繪制列表轉(zhuǎn)換為位圖,然后發(fā)送繪制圖塊命令 DrawQuad 給瀏覽器進程自晰,瀏覽器進程根據(jù) DrawQuad 消息生成頁面,將頁面顯示到顯示器上

優(yōu)點: 我們使用了 CSS 的 transform 來實現(xiàn)動畫效果稍坯,避開了重排重繪階段酬荞,直接在非主線程上執(zhí)行合成動畫操作。這樣的效率是最高的瞧哟,因為是在非主線程上合成混巧,并沒有占用主線程的資源,另外也避開了布局和繪制兩個子階段勤揩,所以相對于重繪和重排咧党,合成能大大提升繪制效率。

五陨亡、常見的觸發(fā)重排傍衡、重繪的屬性和方法

1.引發(fā)重排的操作:

  • 頁面首次渲染深员。
  • 瀏覽器窗口大小發(fā)生改變——resize事件發(fā)生時。
  • 元素尺寸或位置發(fā)生改變——定位蛙埂、邊距倦畅、填充、邊框绣的、寬度和高度叠赐。
  • 元素內(nèi)容變化(文字數(shù)量或圖片大小等等)。
  • 元素字體大小變化屡江。
  • 添加或者刪除可見的DOM元素芭概。
  • 激活CSS偽類(例如::hover)。
  • 設(shè)置style屬性
  • 查詢某些屬性或調(diào)用某些方法惩嘉。

2.引起重排屬性和方法:

width罢洲、 display、 clientWidth宏怔、 offsetWidth奏路、 scrollWidth、 scrollIntoView()臊诊、 
getBoundingClientRect()鸽粉、 height、 border抓艳、 clientHeight触机、 offsetHeight、 
scrollHeight玷或、 scrollTo()儡首、 scrollIntoViewIfNeeded()、 margin偏友、 position蔬胯、 
clientTop、 offsetTop位他、 scrollTop氛濒、 getComputedStyle()、 padding鹅髓、 overflow舞竿、 
clientLeft、 offsetLeft窿冯、 scrollLeft

3.引起重繪的屬性:

color骗奖、 text-decoration、 outline-color、 outline-width执桌、 
border-style鄙皇、 background-image、 outline鼻吮、 box-shadow育苟、 
visibility、 background-position椎木、 outline-style违柏、 
background-size香椎、 background漱竖、 background-repeat、 border-radius

六畜伐、優(yōu)化策略

1.減少DOM操作

  • 最小化DOM訪問次數(shù)馍惹,盡量緩存訪問DOM的樣式信息,避免過度觸發(fā)重排玛界。
  • 如果在一個局部方法中需要多次訪問同一個dom万矾,可以在第一次獲取元素時用變量保存下來,減少遍歷時間慎框。
  • 用事件委托來減少事件處理器的數(shù)量良狈。
  • 用querySelectorAll()替代getElementByXX()。
  • querySelectorAll():獲取靜態(tài)集合笨枯,通過函數(shù)獲取元素之后薪丁,元素之后的改變并不會影響之前獲取后存儲到的變量。也就是獲取到元素之后就和html中的這個元素沒有關(guān)系了
  • getElementByXX():獲取動態(tài)集合馅精,通過函數(shù)獲取元素之后严嗜,元素之后的改變還是會動態(tài)添加到已經(jīng)獲取的這個元素中。換句話說洲敢,通過這個方法獲取到元素存儲到變量的時候漫玄,以后每一次在Javascript函數(shù)中使用這個變量的時候都會再去訪問一下這個變量對應(yīng)的html元素。

2.減少重排

  • 放棄傳統(tǒng)操作DOM的時代压彭,基于vue/react開始數(shù)據(jù)影響視圖模式丽啡。
  • 避免設(shè)置大量的style內(nèi)聯(lián)屬性惦费,因為通過設(shè)置style屬性改變結(jié)點樣式的話励稳,每一次設(shè)置都會觸發(fā)一次reflow算凿,所以最好是使用class屬性凳谦。
  • 不要使用table布局忆畅,因為table中某個元素一旦觸發(fā)了reflow,那么整個table的元素都會觸發(fā)reflow。那么在不得已使用table的場合家凯,可以設(shè)置table-layout:auto;或者是table-layout:fixed這樣可以讓table一行一行的渲染缓醋,這種做法也是為了限制reflow的影響范圍。
  • 盡量少使用display:none可以使用visibility:hidden代替绊诲,display:none會造成重排送粱,visibility:hidden只會造成重繪。
  • 使用resize事件時掂之,做防抖和節(jié)流處理抗俄。
  • 分離讀寫操作(現(xiàn)代的瀏覽器都有渲染隊列的機制)
  • 分離讀寫減少重排的原理
<style>
  #box{
    width:100px;
    height:100px;
    border:10px solid #ddd;
  }
</style>
<body>
  <div id="box"></div>
  <script>
    // 讀寫分離,一次重排
    let box = document.getElementById('box')
    box.style.width='200px';//(寫)js改變樣式世舰,加入渲染隊列中动雹,頓一下,查看下一行是否還是修改樣式跟压,如果是則再加入到渲染隊列胰蝠,一直到下一行代碼不是修改樣式為止
    box.style.height='200px';//(寫)
    box.style.margin='10px';//(寫)
    console.log(box.clientWidth);//(讀)
  </script>
  <script>
    // 沒做到讀寫分離,兩次重排
    box.style.width='200px';//(寫)js改變樣式震蒋,加入渲染隊列中,頓一下茸塞,下一行不是修改樣式的代碼,瀏覽器就會直接渲染一次(重排)
    console.log(box.clientWidth);//(讀)
    box.style.height='200px';//(寫)
    box.style.margin='10px';//(寫)
  </script>
</body>
  • 緩存布局信息
<script>
    // 兩次重排 ’寫‘操作中包含clientWidth屬性查剖,會刷新渲染隊列
    box.style.width = box.clientWidth +10 + 'px'
    box.style.height= box.clientHeight +10 + 'px'
</script>
<script>
    let a=box.clientWidth //(讀)緩存布局信息
    let b=box.clientHeight//(讀)緩存布局信息
    // 一次重排 
    box.style.width = a+10 + 'px' // (寫)
    box.style.height=  b+10 + 'px' // (寫)
</script>

3.css及優(yōu)化動畫

  • 少用css表達式
  • 樣式集中改變(批量處理) 減少通過JavaScript代碼修改元素樣式钾虐,盡量使用修改class名方式操作樣式或動畫;
  • 可以把動畫效果應(yīng)用到position屬性為absolute或fixed的元素上梗搅,這樣對其他元素影響較小
  • 動畫實現(xiàn)的速度的選擇:犧牲平滑度換取速度禾唁。比如實現(xiàn)一個動畫,以1個像素為單位移動這樣最平滑无切,但是reflow就會過于頻繁荡短,大量消耗CPU資源,如果以3個像素為單位移動則會好很多哆键。
  • 開啟css3動畫硬件加速(GPU加速)把渲染計算交給GPU掘托。(能用transform做的就不要用其他的,因為transform可以開啟硬件加速籍嘹,而硬件加速可以規(guī)避重排闪盔。直接跳過重排、重繪辱士,走合成進程)
// 向右移動100px泪掀,一次重排
box.style.left='100px'
// 向右移動200px,不會引發(fā)重排
box.style.ctransform='translateX(200)' 

七颂碘、總結(jié)

重排一定會引起重繪异赫,而重繪不一定會引起重排重繪的開銷較小,重排的代價較高塔拳。在日常開發(fā)過程中應(yīng)該盡量減少重排重繪操作鼠证。


歡迎訪問:天問博客

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市靠抑,隨后出現(xiàn)的幾起案子量九,更是在濱河造成了極大的恐慌,老刑警劉巖颂碧,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件荠列,死亡現(xiàn)場離奇詭異,居然都是意外死亡稚伍,警方通過查閱死者的電腦和手機弯予,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來个曙,“玉大人锈嫩,你說我怎么就攤上這事】寻幔” “怎么了呼寸?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長猴贰。 經(jīng)常有香客問我对雪,道長,這世上最難降的妖魔是什么米绕? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任瑟捣,我火速辦了婚禮,結(jié)果婚禮上栅干,老公的妹妹穿的比我還像新娘迈套。我一直安慰自己,他們只是感情好碱鳞,可當我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布桑李。 她就那樣靜靜地躺著,像睡著了一般窿给。 火紅的嫁衣襯著肌膚如雪贵白。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天崩泡,我揣著相機與錄音禁荒,去河邊找鬼。 笑死角撞,一個胖子當著我的面吹牛呛伴,可吹牛的內(nèi)容都是我干的寥掐。 我是一名探鬼主播,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼磷蜀,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了百炬?” 一聲冷哼從身側(cè)響起褐隆,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎剖踊,沒想到半個月后庶弃,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡德澈,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年歇攻,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片梆造。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡缴守,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出镇辉,到底是詐尸還是另有隱情屡穗,我是刑警寧澤,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布忽肛,位于F島的核電站村砂,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏屹逛。R本人自食惡果不足惜础废,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望罕模。 院中可真熱鬧评腺,春花似錦、人聲如沸手销。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽锋拖。三九已至诈悍,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間兽埃,已是汗流浹背侥钳。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留柄错,地道東北人舷夺。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓苦酱,卻偏偏與公主長得像,于是被迫代替她去往敵國和親给猾。 傳聞我的和親對象是個殘疾皇子疫萤,可洞房花燭夜當晚...
    茶點故事閱讀 43,627評論 2 350

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