css will-change
will-change屬性可以提前通知瀏覽器我們要對(duì)元素做什么動(dòng)畫(huà),這樣瀏覽器可以提前準(zhǔn)備合適的優(yōu)化設(shè)置。這樣可以避免對(duì)頁(yè)面響應(yīng)速度有重要影響的昂貴成本。元素可以更快的被改變,渲染的也更快,這樣頁(yè)面可以快速更新,表現(xiàn)的更加流暢。
舉個(gè)例子,當(dāng)對(duì)于素使用 CSS 3D變形時(shí),元素及其內(nèi)容可以在合成到頁(yè)面之前被創(chuàng)建到我們之前說(shuō)的layer。然而把元素放到layer中是個(gè)昂貴的操作,這將會(huì)導(dǎo)致變形動(dòng)畫(huà)延遲一個(gè)課件的瞬間,也就是flicker
為了避免這種延時(shí),我們可以在發(fā)生之前通知瀏覽器,這樣瀏覽器會(huì)有一定的時(shí)間去準(zhǔn)備這些變化,當(dāng)發(fā)生的時(shí)候layer已經(jīng)準(zhǔn)備好了,這樣動(dòng)畫(huà)酒會(huì)很流暢,不會(huì)閃屏
使用will-change提示瀏覽器關(guān)于即將發(fā)生的變形十分簡(jiǎn)單,添加個(gè)CSS屬性就行
will-change: transform;
也可以告訴瀏覽器要改變?cè)氐臐L動(dòng)條位置,或者多個(gè)要變化的屬性,寫(xiě)下屬性的名字就行,也可以寫(xiě)多個(gè),逗號(hào)隔開(kāi)
will-change: transform, opacity;
聲明了元素即將進(jìn)行的變化會(huì)讓瀏覽器在渲染頁(yè)面時(shí)做更好的決定,這明顯比之前說(shuō)的3D hacks要好。
Load 和 DOMContentLoaded 區(qū)別
Load 事件觸發(fā)代表頁(yè)面中的 DOM,CSS,JS,圖片已經(jīng)全部加載完畢。
DOMContentLoaded 事件觸發(fā)代表初始的 HTML 被完全加載和解析,不需要等待 CSS,JS,圖片加載。
Node 中的 Event loop
防抖
節(jié)流
重繪(Repaint)和回流(Reflow)
重繪和回流是渲染步驟中的一小節(jié),但是這兩個(gè)步驟對(duì)于性能影響很大。
- 重繪是當(dāng)節(jié)點(diǎn)需要更改外觀而不會(huì)影響布局的,比如改變
color就叫稱(chēng)為重繪 - 回流是布局或者幾何屬性需要改變就稱(chēng)為回流。
回流必定會(huì)發(fā)生重繪,重繪不一定會(huì)引發(fā)回流?;亓魉璧某杀颈戎乩L高的多,改變深層次的節(jié)點(diǎn)很可能導(dǎo)致父節(jié)點(diǎn)的一系列回流。
所以以下幾個(gè)動(dòng)作可能會(huì)導(dǎo)致性能問(wèn)題:
- 改變 window 大小
- 改變字體
- 添加或刪除樣式
- 文字改變
- 定位或者浮動(dòng)
- 盒模型
很多人不知道的是,重繪和回流其實(shí)和 Event loop 有關(guān)。
- 當(dāng) Event loop 執(zhí)行完 Microtasks 后,會(huì)判斷 document 是否需要更新。因?yàn)闉g覽器是 60Hz 的刷新率,每 16ms 才會(huì)更新一次。
- 然后判斷是否有
resize或者scroll,有的話會(huì)去觸發(fā)事件,所以resize和scroll事件也是至少 16ms 才會(huì)觸發(fā)一次,并且自帶節(jié)流功能。 - 判斷是否觸發(fā)了 media query
- 更新動(dòng)畫(huà)并且發(fā)送事件
- 判斷是否有全屏操作事件
- 執(zhí)行
requestAnimationFrame回調(diào) - 執(zhí)行
IntersectionObserver回調(diào),該方法用于判斷元素是否可見(jiàn),可以用于懶加載上,但是兼容性不好 - 更新界面
- 以上就是一幀中可能會(huì)做的事情。如果在一幀中有空閑時(shí)間,就會(huì)去執(zhí)行
requestIdleCallback回調(diào)。
以上內(nèi)容來(lái)自于 HTML 文檔
減少重繪和回流
使用 translate 替代 top
<div class="test"></div>
<style>
.test {
position: absolute;
top: 10px;
width: 100px;
height: 100px;
background: red;
}
</style>
<script>
setTimeout(() => {
// 引起回流
document.querySelector('.test').style.top = '100px'
}, 1000)
</script>
使用 visibility 替換 display: none ,因?yàn)榍罢咧粫?huì)引起重繪,后者會(huì)引發(fā)回流(改變了布局)
把 DOM 離線后修改,比如:先把 DOM 給 display:none (有一次 Reflow),然后你修改100次,然后再把它顯示出來(lái)
不要把 DOM 結(jié)點(diǎn)的屬性值放在一個(gè)循環(huán)里當(dāng)成循環(huán)里的變量
for(let i = 0; i < 1000; i++) {
// 獲取 offsetTop 會(huì)導(dǎo)致回流,因?yàn)樾枰カ@取正確的值
console.log(document.querySelector('.test').style.offsetTop)
}
不要使用 table 布局,可能很小的一個(gè)小改動(dòng)會(huì)造成整個(gè) table 的重新布局
動(dòng)畫(huà)實(shí)現(xiàn)的速度的選擇,動(dòng)畫(huà)速度越快,回流次數(shù)越多,也可以選擇使用 requestAnimationFrame
CSS 選擇符從右往左匹配查找,避免 DOM 深度過(guò)深
將頻繁運(yùn)行的動(dòng)畫(huà)變?yōu)閳D層,圖層能夠阻止該節(jié)點(diǎn)回流影響別的元素。比如對(duì)于 video 標(biāo)簽,瀏覽器會(huì)自動(dòng)將該節(jié)點(diǎn)變?yōu)閳D層。