React组件优化是提升应用性能的关键,以下是一些常见的优化策略和工具:
一、React组件优化
避免不必要的重新渲染:
- 使用
React.memo
对函数组件进行记忆化,避免不必要的重渲染。 - 对于类组件,使用
shouldComponentUpdate
或继承React.PureComponent
进行渲染优化。
减少计算量:
- 使用
useMemo
缓存函数的计算结果,仅在依赖项更改时重新计算。 - 使用
useCallback
记忆化函数,减少不必要的重新渲染。
代码分割与动态导入:
- 通过动态导入、
React.lazy
和Suspense
实现按需加载组件,减少初始加载时间。
优化状态管理:
精简父组件状态,谨慎使用Context API
,考虑使用Redux、useReducer等。
- 不必要的渲染:当Context中的值发生变化时,所有消费该Context的组件都会重新渲染,即使它们只依赖于Context值的一部分。这可能导致性能下降,特别是在大型应用中。
- 过度使用:如果Context被过度使用,可能会导致组件树变得复杂,难以维护。
- 可以使用useReducer结合Context:对于复杂的状态逻辑,可以使用useReducer结合Context来管理状态,这样可以提供更好的性能和可维护性
优化组件结构与层次:
- 避免组件深度嵌套,分解大型组件。
对长列表进行虚拟化处理:
- 使用
react-window
或react-virtualized
。
减少内联函数和对象的使用:
- 将函数定义在组件外部,或使用
useCallback
和useMemo
。
避免在JSX中定义匿名函数:
- 将函数定义在JSX外部,并在JSX中传递这些函数的引用。
通过这些优化策略,可以显著提升React应用的性能表现。
二、前端优化
-
将 CSS 放在文件头部,JavaScript 文件放在底部
- CSS 执行会阻塞渲染,阻止 JS 执行
- JS 加载和执行会阻塞 HTML 解析,阻止 CSSOM 构建
如果这些 CSS、JS 标签放在 HEAD 标签里,并且需要加载和解析很久的话,那么页面就空白了。所以 JS 文件要放在底部(不阻止 DOM 解析,但会阻塞渲染),等 HTML 解析完了再加载 JS 文件,尽早向用户呈现页面的内容。
CSS 文件放在头部原因
因为先加载 HTML 再加载 CSS,会让用户第一时间看到的页面是没有样式的、“丑陋”的,为了避免这种情况发生,就要将 CSS 文件放在头部了。
JS 文件也不是不可以放在头部,只要给 script 标签加上 defer 属性就可以了,异步下载,延迟执行。
-
使用浏览器缓存,不重复加载相同的资源
-
为了避免用户每次访问网站都得请求文件,我们可以通过添加 Expires 或 max-age 来控制这一行为。Expires 设置了一个时间,只要在这个时间之前,浏览器都不会请求文件,而是直接使用缓存。而 max-age 是一个相对时间,建议使用 max-age 代替 Expires 。
-
当文件更新了,可以通过更新页面中引用的资源链接地址,让浏览器主动放弃缓存,加载新资源。
-
-
减少http请求、使用 HTTP2
http2优点:
- 解析速度快
- 多路复用:多个请求可以共用一个 TCP 连接
- 提供了首部压缩功能。
-
使用服务端渲染更快
客户端渲染: 获取 HTML 文件,根据需要下载 JavaScript 文件,运行文件,生成 DOM,再渲染。
服务端渲染:服务端返回 HTML 文件,客户端只需解析 HTML。
- 优点:首屏渲染快,SEO 好。
- 缺点:配置麻烦,增加了服务器的计算压力。
客户端渲染过程
- 访问客户端渲染的网站。
- 服务器返回一个包含了引入资源语句和
<div id="app"></div>
的 HTML 文件。 - 客户端通过 HTTP 向服务器请求资源,当必要的资源都加载完毕后,执行
new Vue()
开始实例化并渲染页面。
服务端渲染过程
- 访问服务端渲染的网站。
- 服务器会查看当前路由组件需要哪些资源文件,然后将这些文件的内容填充到 HTML 文件。如果有 ajax 请求,就会执行它进行数据预取并填充到 HTML 文件里,最后返回这个 HTML 页面。
- 当客户端接收到这个 HTML 页面时,可以马上就开始渲染页面。与此同时,页面也会加载资源,当必要的资源都加载完毕后,开始执行
new Vue()
开始实例化并接管页面。
区别就在于第二步。客户端渲染的网站会直接返回 HTML 文件,而服务端渲染的网站则会渲染完页面再返回这个 HTML 文件。
-
静态资源使用 CDN
内容分发网络(CDN)是一组分布在多个不同地理位置的 Web 服务器。当服务器离用户越远时,延迟越高。CDN 通过在多个位置部署服务器,让用户离服务器更近,从而缩短请求时间。
-
使用字体图标 iconfont 代替图片图标
字体图标就是将图标制作成一个字体,使用时就跟字体一样,可以设置属性,例如 font-size、color 等等,非常方便。并且字体图标是矢量图,不会失真。还有一个优点是生成的文件特别小。
-
压缩文件
压缩文件可以减少文件下载时间,让用户体验性更好。
在Webpack中可以通过terser-webpack-plugin
来进行代码压缩,使用image-webpack-loader
来压缩图片 -
减少if else
当条件语句特别多时,可以将 switch 和 if-else 替换为map和对象,或者多态。
三、 CSS性能优化
CSS性能优化是提升网页加载速度和用户体验的关键。以下是一些有效的CSS性能优化方法:
压缩与合并CSS文件
- 压缩CSS文件:通过移除不必要的空格、换行符和注释,减小CSS文件的大小,从而减少加载时间。
- 合并CSS文件:将多个CSS文件合并为一个,减少页面加载时的HTTP请求次数。
优化选择器和属性
- 使用简单的选择器:尽量使用简单的CSS选择器,减少浏览器的匹配时间,提高页面渲染速度。
- 避免使用复杂的选择器:如深层次的嵌套、通配符等,以减少浏览器的匹配时间。
- 减少高代价属性的使用:一些CSS属性,如
box-shadow
、gradients
等,可能会对渲染性能产生较大影响,应在不影响设计的前提下尽量减少这些属性的使用。
优化CSS渲染性能
- 利用CSS硬件加速:通过CSS的
transform
和opacity
属性可以触发GPU加速,从而提高动画和过渡的渲染效率。 - 优化字体加载:只加载网页中实际使用的字符集,以减少字体文件的大小,使用
font-display
属性控制字体的加载和显示策略。
使用CDN加速
- CDN加速:将CSS文件托管在CDN上,可以利用CDN的节点分布优势,将内容缓存到离用户更近的服务器上,从而加快加载速度。
异步加载非关键CSS
- 异步加载非关键CSS:对于非首屏展示的CSS样式,可以考虑使用
<link rel="preload" as="style" href="...">
进行预加载,或者使用JavaScript动态加载,以减少首屏渲染时间。
通过实施这些策略,可以显著提高CSS代码的性能,从而实现更快、更高效的Web页面加载。
四、 js性能优化
JavaScript 性能优化是提升网页和应用响应速度的关键。以下是一些常见的 JavaScript 性能优化方法:
减少 DOM 操作
- 批量 DOM 更新:使用
document.createDocumentFragment()
来批量更新 DOM,减少重绘和回流。 - 缓存 DOM 引用:存储频繁访问的 DOM 元素引用,避免重复查询。
优化循环
- 使用 for 循环代替 forEach:传统 for 循环通常比 forEach 更快。
- 避免重复计算:将数组的长度存储在变量中,而不是在每次迭代时重新计算。
- 使用 Break 和 Continue:用于提前退出循环和跳过不必要的迭代。
利用异步编程
- 使用 async 和 await:使异步代码更易于阅读和维护。
- 优化网络请求:合并网络请求,减少请求数量。
内存管理
- 避免使用全局变量:减少全局变量的使用,防止内存泄漏。
- 使用 WeakMap 进行缓存:在不阻止垃圾回收的情况下缓存对象。
使用 Web Workers
- 多线程:在后台线程中运行脚本,避免阻塞 UI 线程。
代码分割和懒加载
- 代码分割:将代码分割成更小的块,根据需要加载它们。
代码压缩和混淆
- 使用压缩工具:如 UglifyJS、Terser 等,减小文件大小。
- 启用 HTTP 压缩:使用 GZIP 或 Brotli 压缩 JavaScript 文件。
选择合适的数据结构
- 使用 Map 和 Set:提供基于哈希表的存储,提高查找、添加和删除操作的速度。