浅谈前端性能优化之执行渲染优化

515 阅读9分钟

大家好,我是徐徐。今天我们谈谈前端性能优化之执行渲染优化。

前言

前端执行渲染优化是提升网页加载速度和用户体验的关键步骤。随着网页内容和功能的复杂化,如何在保证视觉效果和交互体验的同时,提高页面的渲染效率,成为前端开发中不可忽视的任务。通过优化 CSS、JavaScript、DOM 操作、以及布局和渲染策略等方法,开发者可以有效减少页面的渲染时间,降低性能瓶颈,从而为用户提供更加流畅、快速的浏览体验。下面我们就来看看一些具体的优化方案。

1. CSS优化

image.png CSS 是影响页面渲染性能的重要因素,优化 CSS 可以显著提升页面的渲染效率。通过合理调整 CSS 代码的编写和使用方式,可以有效的达到优化的目的,以下是一些具体的优化措施。

选择器优化

CSS 选择器是浏览器解析样式的基础,复杂的选择器会增加解析的时间。因此:

  • 使用简单、高效的选择器:例如尽量使用 ID 选择器 (#id) 或类选择器 (.class) 而不是复杂的嵌套选择器,选择器越短越好。
  • 避免过度嵌套:嵌套选择器会导致浏览器逐层解析,影响性能。应尽量减少选择器的嵌套层级,保持结构简单。

启用 GPU 加速

某些 CSS 属性可以触发 GPU 加速,利用 GPU 加速可以显著提高动画和过渡效果的性能。

  • 使用transformopacity:这些属性在变换时不会触发重排和重绘,而是直接由 GPU 处理,能大幅提升性能。
  • 合理使用 will-change 属性:提前告诉浏览器某个元素将要发生哪些变化(如 transformopacity),浏览器可以为这些变化做优化准备,但不应滥用 will-change,否则会消耗过多资源。

避免使用 CSS 表达式

CSS 表达式(如在 expression 中写 JavaScript 代码)虽然强大,但会在每次重绘时重新计算,严重影响性能。应尽量避免使用,改用 CSS 变量或其他更高效的方法。

优化重绘

重绘(Repaint)指的是元素的外观改变而导致的重新绘制,不涉及元素布局的变化。通过以下方式减少不必要的重绘:

  • 优先使用 transformopacity:这些属性改变时不会触发重排,只会触发重绘且直接由 GPU 处理,是性能优化的好选择。

利用 CSS contenteditable

对于需要频繁更新的文本内容,使用 contenteditable 属性可以让元素直接在页面上编辑,减少对 DOM 的操作,从而提升性能。需要注意,contenteditable 会带来一些额外的管理工作,如处理输入事件。

2. JavaScript 优化

JavaScript 的执行效率直接影响页面的渲染性能。我们可以通过提升代码执行效率、减少主线程阻塞、合理管理资源加载等方式,来改善网页的渲染性能和用户体验,以下是一些具体的 JavaScript 优化措施。

使用 requestAnimationFrame

requestAnimationFrame 是浏览器专门为高效执行动画而提供的 API。它会在下一次屏幕刷新前调用指定的回调函数,确保动画流畅并且节省资源。

  • 使用场景:动画更新、页面滚动等。通过 requestAnimationFrame 调整动画的每一帧,可以确保动画在最佳的时机更新,避免画面撕裂和卡顿。

降低复杂度或使用 Web Worker

JavaScript 运行在浏览器的主线程上,与页面渲染共享资源。如果 JavaScript 执行过于复杂,可能导致页面卡顿。以下是优化方案:

  • 降低 JavaScript 复杂度:优化算法,减少计算量。
  • 使用 Web Worker:将复杂的计算任务(如数据处理、图像处理)放在 Web Worker 中执行,避免阻塞主线程,提高页面响应速度。

输入处理程序防抖

对于高频率触发的事件(如 scrollresize 等),频繁执行事件处理函数会降低性能。防抖技术可以减少不必要的触发:

  • 使用防抖:在事件被连续触发时,只执行最后一次触发后的处理逻辑,减少性能消耗。常用防抖方法是设置一个延时器,当事件持续触发时延时器不断重置,直到用户停止触发一段时间后再执行操作。

避免强制同步布局

强制同步布局(Forced Synchronous Layout)是指 JavaScript 代码强制让浏览器立即计算布局(如获取元素的宽高、位置等),可能导致多次布局计算,影响性能:

  • 合理安排 DOM 的读写操作:将 DOM 的读取和写入操作分别放在不同的代码块中,避免交替进行,减少强制同步布局的发生。

使用 requestIdleCallback

requestIdleCallback 允许在浏览器空闲时执行非关键任务,这些任务不会阻塞页面的渲染或响应:

  • 使用场景:可以用于延迟执行非关键任务,如统计、日志、预加载等操作。requestIdleCallback 可以根据浏览器的空闲时间来安排任务,确保关键渲染任务优先执行。

3. DOM操作优化

image.png DOM 操作往往是性能瓶颈,优化 DOM 操作可以显著提升渲染性能,下面总结了三种方式。

避免大型、复杂的布局

复杂的布局结构会增加浏览器的计算负担,影响页面渲染速度:

  • 简化布局:通过合理的布局设计,减少不必要的嵌套和复杂性。例如,避免在表格等复杂结构中嵌套大量元素。

防止布局抖动

布局抖动(Layout Thrashing)是指在短时间内频繁改变影响布局的属性,导致多次重排:

  • 避免多次触发布局计算:将需要改变的样式集中到一次修改中,避免连续触发多次重排操作。

批量修改 DOM

每次 DOM 操作都会触发重排和重绘,因此应该将多次 DOM 操作合并为一次,以减少重排重绘的次数:

  • 使用DocumentFragment:在内存中创建一个文档片段,将多次 DOM 操作集中在文档片段中完成,然后一次性将结果添加到实际 DOM 中,减少不必要的渲染。

4. 渲染策略优化

优化渲染策略可以从根本上提升页面性能,指通过减少简化绘制复杂度、以及合理利用分层渲染等技术,来提高浏览器的渲染效率和页面加载性能,下面这些方法你可能用得到。

简化绘制复杂度

复杂的 CSS 效果会增加浏览器的绘制负担,因此应避免使用性能消耗大的效果:

  • 避免使用复杂效果:如阴影、渐变、模糊效果等,这些效果在渲染时需要消耗大量计算资源。可以使用更轻量的效果替代。

减少绘制区域

减少浏览器每次绘制的区域可以提升渲染性能:

  • 使用clip-path:限制元素的绘制区域,只绘制可见部分,从而减少不必要的绘制工作。

实现虚拟滚动

对于包含大量数据的长列表,可以使用虚拟滚动技术,只渲染可视区域内的元素,其他部分的元素不会在 DOM 中渲染:

  • 虚拟滚动:通过动态加载和卸载列表项,显著减少 DOM 节点数量,提升渲染性能。

分层渲染

将页面元素分成不同图层,独立处理每个图层的渲染,减少重绘区域:

  • 分层渲染:通过 CSS 属性(如 transform, opacity)触发图层的创建,将复杂的动画或滚动内容分层处理,提高渲染性能。

离屏渲染

将复杂的绘制任务放到屏幕外完成,绘制完成后再将结果复制到屏幕上显示:

  • 离屏渲染:例如使用 Canvas 元素在屏幕外绘制图形,绘制完成后再将结果复制到实际显示区域,避免频繁更新显示区域。

5. 布局优化

优化页面布局可以减少浏览器的计算负担,提升渲染效率,下面列举两种方法。

使用绝对定位

绝对定位的元素脱离了文档流,不会影响其他元素的布局,因此可以减少页面重排的次数:

  • 绝对定位:将那些不会影响整体布局的元素使用 position: absolutefixed 定位,减少重排开销。

避免回流

回流(Reflow)是指当 DOM 发生变化,导致元素尺寸、布局或位置变化时,浏览器需要重新计算元素的位置和大小。避免回流可以减少浏览器的计算负担:

  • 减少布局影响:尽量避免频繁修改影响布局的属性,如 width, height, margin 等。如果必须修改这些属性,尽量合并为一次操作。

6. 可见性和懒加载优化

提高页面初次加载速度,并优化用户体验,可以使用可见性和懒加载技术。

使用 Intersection Observer

Intersection Observer 是一个浏览器 API,可以高效地检测元素是否进入视口,从而实现懒加载等功能:

  • 懒加载图像:只有当图像进入视口时才加载图像文件,减少初始加载时间。
  • 懒加载其他资源:例如延迟加载不在视口中的视频、广告等内容,避免阻塞页面渲染。

通过以上这些优化措施,可以显著提高页面的渲染性能,提升用户的浏览体验。

结语

上面提到的一些执行渲染优化方案是比较常见的一些方案,至于在实际使用的过程中可根据自己的应用场景去使用,不过大体的方向可以从上面 6 个大方向去思考。不知道你在日常开发中是否有用到这些方案,欢迎和我一起讨论。

原文链接

mp.weixin.qq.com/s/sQNipm70b…