前端渲染機(jī)制及重繪/回流

渲染機(jī)制

渲染步驟

瀏覽器的渲染機(jī)制一般分為以下幾個(gè)步驟:

1. 處理 HTML 并構(gòu)建 DOM 樹兄墅。
2. 處理 CSS 構(gòu)建 CSSOM 樹美尸。
3. 將 DOM 與 CSSOM 合并成一個(gè)渲染樹。
4. 根據(jù)渲染樹來布局拓挥,計(jì)算每個(gè)節(jié)點(diǎn)的位置。
5. 調(diào)用 GPU 繪制,合成圖層镜雨,顯示在屏幕上。

注意:

  • 在構(gòu)建 CSSOM 樹時(shí)儿捧,會(huì)阻塞渲染荚坞,直至 CSSOM 樹構(gòu)建完成。并且構(gòu)建 CSSOM 樹是一個(gè)十分消耗性能的過程菲盾,所以應(yīng)該盡量保證層級(jí)扁平颓影,減少過度層疊,越是具體的 CSS 選擇器懒鉴,執(zhí)行速度越慢诡挂。
  • 當(dāng) HTML 解析到 script 標(biāo)簽時(shí),會(huì)暫停構(gòu)建 DOM临谱, 完成后才會(huì)從暫停的地方重新開始璃俗。也就是說,如果你想首屏渲染的越快悉默,就越不應(yīng)該在首屏就加載 JS 文件旧找。并且 CSS 也會(huì)影響 JS 的執(zhí)行,只有當(dāng)解析完樣式表才會(huì)執(zhí)行 JS麦牺,所以也可以認(rèn)為這種情況下钮蛛,CSS 也會(huì)暫停構(gòu)建 DOM。

Load 和 DOMContentLoaded 區(qū)別

  • Load 事件觸發(fā)代表頁面中的 DOM剖膳,CSS魏颓,JS,圖片已經(jīng)全部加載完畢吱晒。
  • DOMContentLoaded 事件觸發(fā)代表初始的 HTML 被完全加載和解析甸饱,不需要等待 CSS,JS仑濒,圖片加載叹话。

圖層

一般來說,可以把普通文檔流看成一個(gè)圖層墩瞳。特定的屬性可以生成一個(gè)新的圖層驼壶。不同的圖層渲染互不影響,所以對(duì)于某些頻繁需要渲染的建議單獨(dú)生成一個(gè)新圖層喉酌,提高性能热凹。但也不能生成過多的圖層泵喘,會(huì)引起反作用。

通過以下幾個(gè)常用屬性可以生成新圖層

  • 3D 變換:translate3d般妙、translateZ
  • will-change
  • video纪铺、iframe 標(biāo)簽
  • 通過動(dòng)畫實(shí)現(xiàn)的 opacity 動(dòng)畫轉(zhuǎn)換
  • position: fixed

重繪(Repaint)和回流(Reflow)

概念

重繪和回流是渲染步驟中的一小節(jié),但是這兩個(gè)步驟對(duì)于性能影響很大碟渺。

  • 重繪是 當(dāng)節(jié)點(diǎn)需要更改外觀而不會(huì)影響布局的鲜锚,比如改變 colorbackground-color苫拍、visibility等就叫稱為重繪
  • 回流是 布局或者幾何屬性需要改變 就稱為回流烹棉。

注意: 回流必定會(huì)發(fā)生重繪,重繪不一定會(huì)引發(fā)回流怯疤。回流所需的成本比重繪高的多催束,改變深層次的節(jié)點(diǎn)很可能導(dǎo)致父節(jié)點(diǎn)的一系列回流集峦。

會(huì)導(dǎo)致回流的操作:

  • 頁面首次渲染
  • 瀏覽器窗口大小發(fā)生改變
  • 元素尺寸或位置發(fā)生改變
  • 元素內(nèi)容變化(文字?jǐn)?shù)量或圖片大小等等)
  • 元素字體大小變化
  • 添加或者刪除可見DOM元素
  • 激活CSS偽類(例如::hover
  • 查詢某些屬性或調(diào)用某些方法

一些常用且會(huì)導(dǎo)致回流的屬性和方法:

  • clientWidthclientHeight抠刺、clientTop塔淤、clientLeft
  • offsetWidthoffsetHeight速妖、offsetTop高蜂、offsetLeft
  • scrollWidthscrollHeight罕容、scrollTop备恤、scrollLeft
  • scrollIntoView()scrollIntoViewIfNeeded()
  • getComputedStyle()
  • getBoundingClientRect()
  • scrollTo()

重繪和回流與Event loop關(guān)系

很多人不知道的是锦秒,重繪和回流其實(shí)和 Event loop 有關(guān)露泊。

1. 當(dāng) Event loop 執(zhí)行完 Microtasks 后,會(huì)判斷 document 是否需要更新旅择。因?yàn)闉g覽器是 60Hz 的刷新率惭笑,每 16ms 才會(huì)更新一次。
2. 然后判斷是否有 resize 或者 scroll 生真,有的話會(huì)去觸發(fā)事件沉噩,所以 resizescroll 事件也是至少 16ms 才會(huì)觸發(fā)一次,并且自帶節(jié)流功能柱蟀。
3. 判斷是否觸發(fā)了 media query
4. 更新動(dòng)畫并且發(fā)送事件
5. 判斷是否有全屏操作事件
6. 執(zhí)行 requestAnimationFrame 回調(diào)
7. 執(zhí)行 IntersectionObserver 回調(diào)川蒙,該方法用于判斷元素是否可見,可以用于懶加載上长已,但是兼容性不好
8. 更新界面
9. 以上就是一幀中可能會(huì)做的事情派歌。如果在一幀中有空閑時(shí)間弯囊,就會(huì)去執(zhí)行 requestIdleCallback 回調(diào)。

減少重繪和回流

  • 使用 translate 替代 top
  • 使用 visibility 替換 display: none 胶果,因?yàn)榍罢咧粫?huì)引起重繪匾嘱,后者會(huì)引發(fā)回流(改變了布局)
  • 把 DOM 離線后修改,比如:先把 DOM 給 display:none (有一次 Reflow)早抠,然后你修改 100 次霎烙,然后再把它顯示出來
  • 不要把 DOM 結(jié)點(diǎn)的屬性值放在一個(gè)循環(huán)里當(dāng)成循環(huán)里的變量
  • 不要使用 table 布局,可能很小的一個(gè)小改動(dòng)會(huì)造成整個(gè) table 的重新布局
  • 動(dòng)畫實(shí)現(xiàn)的速度的選擇蕊连,動(dòng)畫速度越快悬垃,回流次數(shù)越多,也可以選擇使用 requestAnimationFrame
  • CSS 選擇符從右往左匹配查找甘苍,避免 DOM 深度過深
  • 將頻繁運(yùn)行的動(dòng)畫變?yōu)閳D層尝蠕,圖層能夠阻止該節(jié)點(diǎn)回流影響別的元素。比如對(duì)于 video 標(biāo)簽载庭,瀏覽器會(huì)自動(dòng)將該節(jié)點(diǎn)變?yōu)閳D層看彼。

CSS

  • 避免使用table布局。
  • 盡可能在DOM樹的最末端改變class囚聚。
  • 避免設(shè)置多層內(nèi)聯(lián)樣式靖榕。
  • 將動(dòng)畫效果應(yīng)用到position屬性為absolutefixed的元素上。
  • 避免使用CSS表達(dá)式(例如:calc())顽铸。

JavaScript

  • 避免頻繁操作樣式茁计,最好一次性重寫style屬性,或者將樣式列表定義為class并一次性更改class屬性谓松。
  • 避免頻繁操作DOM星压,創(chuàng)建一個(gè)documentFragment,在它上面應(yīng)用所有DOM操作鬼譬,最后再把它添加到文檔中租幕。
  • 也可以先為元素設(shè)置display: none,操作結(jié)束后再把它顯示出來拧簸。因?yàn)樵?code>display屬性為none的元素上進(jìn)行的DOM操作不會(huì)引發(fā)回流和重繪劲绪。
  • 避免頻繁讀取會(huì)引發(fā)回流/重繪的屬性,如果確實(shí)需要多次使用盆赤,就用一個(gè)變量緩存起來贾富。
  • 對(duì)具有復(fù)雜動(dòng)畫的元素使用絕對(duì)定位,使它脫離文檔流牺六,否則會(huì)引起父元素及后續(xù)元素頻繁回流颤枪。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市淑际,隨后出現(xiàn)的幾起案子畏纲,更是在濱河造成了極大的恐慌扇住,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,000評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件盗胀,死亡現(xiàn)場離奇詭異艘蹋,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)票灰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門女阀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人屑迂,你說我怎么就攤上這事浸策。” “怎么了惹盼?”我有些...
    開封第一講書人閱讀 168,561評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵庸汗,是天一觀的道長。 經(jīng)常有香客問我手报,道長蚯舱,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,782評(píng)論 1 298
  • 正文 為了忘掉前任昧诱,我火速辦了婚禮,結(jié)果婚禮上所袁,老公的妹妹穿的比我還像新娘盏档。我一直安慰自己,他們只是感情好燥爷,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,798評(píng)論 6 397
  • 文/花漫 我一把揭開白布蜈亩。 她就那樣靜靜地躺著,像睡著了一般前翎。 火紅的嫁衣襯著肌膚如雪稚配。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,394評(píng)論 1 310
  • 那天港华,我揣著相機(jī)與錄音道川,去河邊找鬼。 笑死立宜,一個(gè)胖子當(dāng)著我的面吹牛冒萄,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播橙数,決...
    沈念sama閱讀 40,952評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼尊流,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了灯帮?” 一聲冷哼從身側(cè)響起崖技,我...
    開封第一講書人閱讀 39,852評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤逻住,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后迎献,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體瞎访,經(jīng)...
    沈念sama閱讀 46,409評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,483評(píng)論 3 341
  • 正文 我和宋清朗相戀三年忿晕,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了装诡。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,615評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡践盼,死狀恐怖鸦采,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情咕幻,我是刑警寧澤渔伯,帶...
    沈念sama閱讀 36,303評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站肄程,受9級(jí)特大地震影響锣吼,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蓝厌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,979評(píng)論 3 334
  • 文/蒙蒙 一玄叠、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧拓提,春花似錦读恃、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蹦疑,卻和暖如春西雀,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背歉摧。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評(píng)論 1 272
  • 我被黑心中介騙來泰國打工艇肴, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人叁温。 一個(gè)月前我還...
    沈念sama閱讀 49,041評(píng)論 3 377
  • 正文 我出身青樓豆挽,卻偏偏與公主長得像,于是被迫代替她去往敵國和親券盅。 傳聞我的和親對(duì)象是個(gè)殘疾皇子帮哈,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,630評(píng)論 2 359

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

  • 發(fā)送 & 接收信息 數(shù)據(jù)是以“數(shù)據(jù)包”的形式通過互聯(lián)網(wǎng)發(fā)送,而數(shù)據(jù)包以字節(jié)為單位锰镀。當(dāng)你編寫一些 HTML娘侍、CSS ...
    IT界中小PQ閱讀 407評(píng)論 0 0
  • 發(fā)送 & 接收信息 數(shù)據(jù)是以“數(shù)據(jù)包”的形式通過互聯(lián)網(wǎng)發(fā)送咖刃,而數(shù)據(jù)包以字節(jié)為單位。當(dāng)你編寫一些 HTML憾筏、CSS ...
    mongofeng閱讀 921評(píng)論 0 0
  • 前言 瀏覽器的內(nèi)核是指支持瀏覽器運(yùn)行的最核心的程序嚎杨,分為兩個(gè)部分的,一是渲染引擎氧腰,另一個(gè)是JS引擎枫浙。渲染引擎在不同...
    浪里行舟閱讀 1,531評(píng)論 0 13
  • 作者: 前端工匠 公號(hào) / 浪里行舟 (本文來自作者投稿) 前言 瀏覽器的內(nèi)核是指支持瀏覽器運(yùn)行的最核心的程序,分...
    一個(gè)敲代碼的前端妹子閱讀 735評(píng)論 1 5
  • 第八節(jié) 稅收優(yōu)惠 一古拴、免稅收入 二箩帚、免征與減征優(yōu)惠 三、高新技術(shù)企業(yè)優(yōu)惠
    飛翔_9215閱讀 96評(píng)論 0 0