重绘和重排
重绘
元素的外观发生改变时,浏览器重新绘制元素的过程。比如颜色、背景、边框等的变化,会导致页面元素的重新渲染,但不会影响元素的布局和位置。
-
触发原因:仅影响元素的视觉外观属性。例如:
color、background-color、visibility的变化outline、box-shadow的变化
-
性能影响:重绘相对来说消耗的性能较低,因为它不涉及元素的重新布局。它只需要更新屏幕上元素的显示。
重排
通过css和js修改了元素的几何属性,浏览器就要重新计算,进行布局和酒席,这个过程就叫重排,也叫回流。
-
触发原因:任何会改变页面布局的操作。例如:
- 添加或删除 DOM 元素
- 改变元素的尺寸(如
width、height) - 改变内容(如文本增加或减少)
- 改变页面的
margin、padding、border、position等属性 - 浏览器窗口大小改变时
-
性能影响:重排是非常消耗性能的操作,因为它会导致页面的布局重新计算,甚至可能影响整个页面的布局,特别是在涉及复杂布局时。
减少的方法
避免直接操作 DOM
频繁操作 DOM 会导致性能下降。应尽可能减少对 DOM 元素的直接操作。例如,可以通过 DocumentFragment 或 innerHTML 一次性批量更新多个元素。
使用 class 而不是直接修改样式
直接修改元素样式可能会触发重排。使用 classList 更加高效,因为它减少了样式修改带来的重排次数。
缓存布局信息
如果在循环中频繁获取布局信息(如 offsetWidth、offsetHeight),会导致浏览器重复计算布局。可以提前缓存布局信息。
防抖和节流
防抖
防抖是指在连续触发事件中,只在最后一次触发结束后的一段时间内执行一次函数。如果在这段时间内再次触发,则重新计时。它可以避免在短时间内多次触发函数。
- 定义:在连续事件触发时,只有在最后一次触发结束后的延迟时间内没有再次触发事件,才会执行函数。
- 应用场景:适用于用户输入、搜索框输入等场景,这类操作希望在用户停止输入后再进行处理,避免在每次输入时都触发查询。
实现原理:通过设置一个定时器,如果在规定时间内事件再次触发,就会清除上一次的定时器,重新计时。
示例:输入框防抖,在用户停止输入后的 300 毫秒执行函数。
节流
在一段时间内只允许一次函数执行,即使这个时间段内事件被频繁触发。它可以确保某个操作在特定时间间隔内只执行一次,控制事件触发频率。
- 定义:在连续触发事件中,保证在指定时间间隔内只执行一次函数。
- 应用场景:适用于持续性事件,如窗口滚动、页面缩放、鼠标移动等。这些事件可能会频繁触发,但只需要在一定时间内执行一次操作。
实现原理:通过一个时间戳或定时器来记录上一次执行的时间,如果当前时间距离上次执行的时间超过了设定的间隔时间,就执行函数。 示例:滚动事件节流,每 200 毫秒只触发一次事件。
区别和选择
-
防抖:在持续触发的情况下,函数只会在停止触发后的一段时间才执行。适合希望只在事件停止后才进行操作的场景。
- 例子:搜索框中的输入,只在用户停止输入后才发送请求。
-
节流:在持续触发的情况下,函数会按照固定的时间间隔执行。适合需要频繁执行操作但不希望触发过于频繁的场景。
- 例子:滚动条事件中定时更新页面内容、鼠标移动时定时执行某些操作。
如果希望函数定期执行,那么使用节流。
如果希望函数在最后一次操作结束后执行,那么使用防抖。
使用性能分析工具
其他性能优化技巧
掘金课程中有讲到调试技巧,地址:前端开发调试之 PC 端调试 - 掘金 (juejin.cn)
使用 requestAnimationFrame 代替 setTimeout / setInterval
在需要进行动画效果时,使用 requestAnimationFrame 更加平滑和高效,因为它与浏览器的刷新率同步,避免了不必要的重绘。
延迟加载(Lazy Loading)
对于图片或大型资源,可以使用延迟加载技术,在用户需要时才加载,以减少页面初始加载时间。
<img src="placeholder.jpg" data-src="real-image.jpg" class="lazy-load" alt="Lazy Image">
使用 JavaScript 监听 scroll 事件并判断图片是否进入视口,然后加载实际资源。
4.3 使用 Web Workers
对于复杂的计算操作,可以使用 Web Workers 在后台线程执行,避免阻塞主线程。