前言
性能优化是目前在面试中被问到非常多的问题,主要就是通过各种算和技术来提高页和应用的速度和用户体前端性能优化的问题并不好回答
在回答的时候干万不要掉进一个误区,认为性能优化只是几个技术点而已,事实上性能优化涉及到的是多方面的
我们首先需要知道,当一个项目出现性能问题时,并不是突然发生了,而是日积月累的结果,所以对于一个项目来说,最好的性能优化应该是从平时开发过程中就要去注意和实现的
三个层面
所以接下来我们会从三个层面来聊一聊性能优化的内容,包括
- 项目架构
- 项目开发
- 项目部署
项目架构
为什么架构设计会影响性能呢?
俗话说如果战略如果错误那么在战术再怎么优秀也无法弥补失败。在真实开发中,性能优化并不是一朝一夕的事情,如果等到我们的项目出现严重的性能问题,再去解决,往往会成为一坨大粪代码
那么架构设计需要考虑哪些因素
主要是两方面的因素协同开发、模块解耦。
项目架构的因素
协同开发
这是指多个开发人员能够有效地一起工作,减少冲突和重复工作
良好的架构可以帮助团队成员独立开发各自的模块,而不必过于依赖其他人
另外当我们出现人员流动时(有人入职或者离职),可以快速的应对。
有人入职,可以快速分配任务,协作开发。
有人离职,不影响其他模块的迭代,项目有序推进。
这是一个好的项目架构的前提
模块解耦
解耦是指在设计和开发过程中,使各模块之间的依赖最小化
能够使代码更加灵活 易于维护和扩展 这对于大型项目或者长期维护项目非常重要,因为它降低了修改某个模块时对其他模块的影响
尽量每个模块需要做到高内聚 低耦合
项目架构的实现(一)采用模块化的架构设计
Utils工具封装模块:
- 将项目中通用的工具函数封装在utils目录中,比如日期格式化函数、数据处理函数等
- 这些工具函数应该是纯函数,保证输入相同输出相同,不依赖于外部状态
- 将工具函数分模块管理,并在index.js中集中导出,以便在项目的其他地方直接导入使用
Store状态管理模块:
- 在Vue项目中,可以通过Pinia的模块化设计来管理状态
- 每个页面或功能模块有自己的store模块,如userStorejs、productStorejs等
- 同时,可以创建一个公共store模块commonStore.js用于存放应用级别的状态,如全局loading状态等
- 组件、页面的模块开发
Vue源码相关架构
- 从大的模块来说,它的渲染器、编译器、响应式系统是划分清晰的
- 响应式系统和编译器可以作为独立的模块来开发和使用,渲染器依赖于响应式系统和编译器
- 从小的模块来说,它的调度系统、watch、watchEffect等又单独做了分离,包括keep-alive、suspense、teleport都可以作为一个独立的模块来开发,再集成到整个Vue项目中。
项目架构的实现二 其他方面的设计
Webpack和Vite的优化
代码分割(CodeSplitting):Webpack和Vite都支持代码分割,这有助于只加载需要的模块,减少初始加载时间并提高性能
动态导入(DynamicImport):使用动态导入可以根据需要懒加载模块,进一步降低加载时间。
TreeShaking:通过去除未使用的代码来优化最终输出文件的大小。Webpack和Vite都有内置的支持
使用版本控制和分支策略
Git工作流:团队可以采用Git工作流,比如GitFlow,以确保开发人员在不同的分支上独立工作,然后通过合并请求(pullrequests)进行代码审查和集成
代码审查codereview:代码审查是协同开发的重要部分,确保代码质量和一致性,同时让团队成员对代码变更保持透明(包括ESlint、Prettier等)
其他方面的考虑
持续集成/持续部署(CI/CD)工具的使用:利用CI/CD管理和自动化部署流程,确保团队开发的一致性,提高测试和部署的效率
文档和沟通:良好的文档、沟通机制来确保团队协同工作,特别是在项目架构和代码约定方面
项目开发
项目开发框架相关优化(Vue)
合理使用v-if和v-show
v-if用于条件变化不频繁的场景,避免不必要的组件创建和销毁
v-show用于频繁切换显示状态的场景,通过控制CSS的display属性来提升性能避免不必要的组件染:
避免不必要的组件重渲染
使用key确保组件唯一性,避免不必要的DOM更新
使用v-once指令确保不变的数据只渲染一次。
合理使用Vue生命周期勾子,控制组件是否需要重新渲染
组件懒加载(LazyLoading)
使用动态import实现按需加载组件,减少初始加载时间
使用Vue的computed
使用computed属性缓存计算结果,避免重复计算
状态下沉
根据虚拟DOM更新特性,将状态下沉到子组件,避免全局或父组件频繁更新
合理使用Keep-Alive
使用<keep-alive>组件缓存动态组件,避免不必要的组件销和创建
项目开发-公共开发代码优化
减少不必要的计算
避免在染过程中进行大量计算,将重计算操作放在适当位置,如computed或方法调用
抖动(Debouncing)和节流(Throttling)
在频繁触发的事件(如滚动、输入)上使用去抖动和节流,减少事件处理频率
优化循环和选代
优化循环使用,比如获取长度在外部获取arr.length,避免在循环中创建新对象和数组等
使用WebWorkers
将繁重计算任务移到WebWorkers中,避免阻塞主线程,保持流畅性
避免内存泄漏
在组件销毁时清理定时器、事件监听器,闭包小心内存泄漏等资源,避免内存泄漏
使用现代图片格式和精图
使用WebP、AVIF等格式减少图片文件大小,加快加载速度,对图片进行压缩处理。
精灵图的使用,页面只需要发送一次请求来加载这张大图,而不是为每个小图标发送多个请求,这可以显著减少HTTP请求的数量,降低网络开销。
图片懒加载
使用懒加载技术只加载可视区域的图片,减少初始加载时间和带宽消耗CSS选择器优化
使用简单有效的选择器,避免复杂的选择器链,提高染性能
避免回流和重绘
尽量减少DOM操作,使用批量更新,优化回流和重绘性能。
使用transform和opacity进行动画效果,避免触发回流
使用CSS动画
优先使用CSS动画而JavaScript动画,提升性能
项目开发-其他方面优化
服务端渲染(SSR):
SSR(服务端染)是在服务器端预先染页面,并将完整的HTML发送到客户端SSR提高了首屏染速度,特别适用于SEO需求强的项目和需要快速加载的应用
代码压缩和混滑
使用Terser等工具压缩JavaScript,减少文件大小
压缩CSS和HTML文件,优化代码传输速度
按需加载和代码拆分
使用Webpack、vite等工具实现代码拆分,按需加载模块
第三方包按需引入
使用Babel插件或Vite配置,按需引入UI库组件,减小打包体积
使用虚拟列表等技术
在处理长列表时,使用虚拟滚动技术,只染可视区域的元素,提升性能
项目部署 优化手段
CDN使用和配置
CDN(内容分发网络)是一组分布在多个地理位置的服务器,用于加速静态资源(如图片、CSS、JavaScript文件等)的传输通过将资源缓存到离用户更近的服务器上,CDN可以显著减少资源加载时间,提升用户体验 。选择可靠的CDN提供商,根据目标用户群体的位置选择最佳的CDN服务器节点。
将静态资源托管到CDN提供商(如阿里云、腾讯云、Cloudflare、AWSCloud等)上
配置构建工具(如Webpack或vite)输出静态资源的路径
首屏渲染速度优化
将首屏染所需的关键CSS内联到HTML中,减少CSS阻塞染的时间,也可以整合网络请求。
使用async或defer属性来异步加载JavaScript脚本,避免阻塞染
通过按需加载(LazyLoading)和代码分割(CodeSplitting)技术,将非关键代码分 减少初始加载时间。
当然也包括我们前面架构中提到的SSR技术。
HTTP缓存策略
HTTP缓存策路通过在客户端缓存静态资源 避免重复请求,减少服务器负载和页面加载时间。
设置适当的HTTP缓存头(如Cache-Control、ETag和Expires),为静态资源设置缓存策略
根据文件的特性,设置强制缓存(Cache-Control和Expires),比如JS文件、CSS文件等(可以结合文件指纹hash,在文件更新时文件生成新的文件名,让客户端可以加载新的文件)。
对于频繁更新的文件,使用协商缓存((ETag和Last-Modified)),比如如果HTML页面经常变更(可以让浏览器根据页面内容变化判断是否需要重新加载)。
代码压缩和优化
代码压缩和优化是通过去除多余的空格、注、代码缩 (例如将变量名缩短) 当然也包括Treeshaking等方式减少文件大小 加快传输速度
使用构建工具(如Webpack ite)压缩插件(如Terser)对JavaScript代码行压缩和优化 玉缩CSS和HTML文件,减少文件体积。
可以使用诸如TinyPNG、mageoptim、 squoosh等工具对图片进行压缩 减少图片文件的大小
对图标和简单的图形 可以使用SVG格式 这种格式不仅文件小 而且可以无损缩放。
文件压缩是通过压缩算法(如gzip、减少文件体积的技术,可以显著减少文本文件(如HTML、CSS、JavaScript)和部分图像文件的体积,降低网络传输时间(实现也非常简单,在服务器中中启用gzip或Brotli压缩即可)。
减少和优化资源请求
减少DNS查询 通过将多个资源托管在一域名下,减少DNS查询的时间。
对于必须跨域的资源,使用DNS预解析(<link rel=dns-prefetch”href=//zhaimou.com”>)
通过异步加载或延加载(如使用async或defer)减少第三方脚本对页面加载速度的影响。
预加载(Preload)和预获取(Prefetch):
使用<linkrel=“preload href=”/path/to/resourceas=script/style>来预加载关键资源
使用<linkrel=“prefetch” href=”/path/to/resource">来预获取未来可能需要的资源!
文章到这里就结束了,更多作为自我学习,也希望对你有所帮助