冲刺大厂你需要知道的前端性能优化

9 篇文章 0 订阅
2 篇文章 0 订阅

前端性能优化是前端面试过程中永远逃不开的问题,尤其是针对代码量巨大的单页应用,优化更为重要。这里结合项目经历,总结一下项目中做过的性能优化。

首先,我们需要思考一下,前端出现性能问题可能有哪些层面的原因?加载速度慢?页面运行卡,动画卡顿不流畅?

所以,从用户角度来看,前端性能优化可以分为两个方面。一个是页面加载的很快,另一个是页面使用起来很流畅。因此,对性能优化的探索,我们可以分为页面加载时间跟页面运行效率两个方向来进行研究。

1. 页面加载速度

移动端一个h5页面,从用户点 H5 链接到页面渲染完成展示给用户,需要经历的过程,如下图:在这里插入图片描述
其中 Webview 容器初始化、静态资源加载以及对后端接口的请求,耗时是比较多的,并且这个耗时页面一定处于白屏阶段,项目中通常会对这三块给出一些常规的优化方案,渲染的耗时优化本文不论述。

1.1 webview容器初始化

我们采用过业界常用的全局WebView的方式,在我们的rn首页,我们会在用户进入首页时候,就初始化一个后续资源页面的的WebView待用,并隐藏,当点击查询进入资源页面的时候,直接使用这个WebView加载对应网页,并展示。

1.2 静态资源加载优化

这块涉及到的内容很多,主要是通过webpack打包机制,浏览器缓存机制,cdn加速,域名扩展等方式优化静态资源。

1.2.1 webpack打包机制
  • 这块可以配合浏览器的缓存机制一起考虑。浏览器缓存结合通过webpack打包给静态资源路径中加入hash的方式共同控制静态资源(背景:为了利用浏览器和 CDN 的缓存,通常会给静态资源设置一个比较长的缓存时间,在有内容更新的时候,通过在静态资源路径中加入 hash 的方式来使缓存失效,更新文件。)
    具体使用可以参考下面其他部分
  • 使用splitChunks对公共代码进行分包,避免公共代码被重复打包加载。
  • 按需加载,相应页面加载其对应代码使用按需加载(懒加载)的方式可以有效提高页面性能(import().then()、require.ensure)
1.2.2 骨架屏

骨架屏也是在移动端页面首屏优化的一个重要手段,在页面数据未准备好的情况,相比与枯燥的白屏页面而言,展示骨架屏能给用户一个好的感官体验。但是如何生成质量高的骨架屏也是一个难点,需要综合考虑 ROI 来选择是否使用骨架屏。

1.2.3 完善的cdn和缓存方案
  • 对变化比较少的资源配置超长时间的本地缓存 — 节省带宽
  • 对资源采用内容摘要作为缓存更新依据 — 精确的缓存控制静态资源
  • 静态资源实现CDN部署 —优化网络请求
  • 更资源发布路径实现非覆盖式发布 — 平滑升级
1.2.4 SSR服务端渲染
1.2.5 其他
  • 使用多个域名,将同一页面的资源分散到不同域名下,提升连接上限。 Chrome有个机制,同一个域名同时最多只能建立6个TCP连接
  • 资源请求合并,过多分散的资源包会产生过多的网络请求,但也不能随意合并,最佳的方式是按照页面或者模块进行划分,并配置 async 属性来异步加载 script 脚本。
  • 资源压缩
1.3. 数据请求的优化
  • 请求合并,对多个接口请求合并处理,可以采用在后端提供接口的基础上,在进行node端的一层包装,以获得更符合前端Ui的数据模型。
1.4 渲染优化
2.1 css和js的装载
  • css 样式表置顶,防止页面在没有css样式的情况下渲染出来
  • js 脚本置底,不阻塞页面的渲染和css的加载,使css资源尽量在第一批并发下载中,让页面更快的呈现给用户。
  • 合理使用js的异步加载(defer/aysnc)
2.2 尽量避免避免重排和重绘
  • 用translate(重绘)替代top(回流)改变
  • 批量修改dom
  • 添加 CSS3 样式启用 GPU 硬件加速
  • 优化dom操作

2. 页面运行流畅

为了保证页面运行效率,快速响应用户的交互,主要需要进行的是代码层面的优化。

  • 简单动画尽量只使用transform、opacity、transition等属性完成
  • 使用requestAnimationFrame代替setTimeout、setInterval控制动画频率
  • 对将要使用动画的部分,开启GPU硬件加速
  • 对高频触发事件使用防抖或者节流
  • 框架层面的优化,比如在使用react的时候,通过合理的使用shouldcomponetupdate或者hooks来减少不必要的render。
  • 事件委托,利用事件冒泡的机制来处理子元素事件的绑定,将子元素的 DOM 事件,交由它们的父元素来进行处理,可以有效降低页面的开销等
  • 懒加载
  • 虚拟列表,像原生APP一样,只渲染可视区域,但是给用户无感知的滚动体验。

其他部分

1. webpack输出文件的hash, chunkhash, contenthash?

通过一个例子说明:

module.exports = {
  entry: {
      main:"main.js"  // 业务代码
  },
  output: {
    path: "/dist",
    // filename: "[name].[hash].js"
    filename: "[name].[chunkhash].js"
  },
  optimization: {
  		moduleIds: 'hashed',
        splitChunks: {
            cacheGroups: {
                commons: {
                    test: /[\\/]node_modules[\\/]/,
                    name: "vendors",  // 公共模块
                    chunks: "all"
                }
            }
        }
    }
}

output.filename, 如果采用hash的话,main和公共模块vendor的hash值会相同,这就有一个问题,每次业务代码改变也会导致公共模块改变。

如果采用chunkhash,它会使用它自己的模块中的内容来生成哈希值, vendor和main就会有不同的hash值,业务代码改变也不会导致公共模块改变。

但是还有一个问题,随着业务依赖的增加,比如main中增加了依赖,我们打包的时候希望只有main文件的hash改变,而事实是main和vendor都变化了,这不是我们所希望的,这个和webpack的chuckid有关,当你增加了依赖,vendor默认的chunkid变化了就会重新生成hash,这时候可以使用webpack 4提供的moduleIds: ‘hashed’,来固定公共包。

除了chunkhash,还可以使用更精确的contenthash,举个例子,如果在源码中,index.css被index.js引用了,所以共用相同的chunkhash值。但是这样子有个问题,如果index.js更改了代码,css文件就算内容没有任何改变,由于是该模块发生了改变,导致css文件会重复构建,这时候可以用contenthash。

2 ManifestPlugin插件的使用

在SSR开发时,前端打包后,node后端就可以通过这个json数据,返回正确资源路径的html模板

3. RAF:requestAnimationFrame

动画是由浏览器按照一定的频率一帧一帧的绘制的,由css实现的动画的优势就是浏览器知道动画的开始及每一帧的循环间隔,能够在恰当的时间刷新UI,给用户一种流畅的体验,而js的setInterval或setTimeout实现的JavaScript动画就没有这么可靠了,因为浏览器压根就无法保证每一帧渲染的时间间隔,一般情况下,每秒平均刷新次数能够达到60帧,就能够给人流畅的体验,即每过 1000/60 毫秒渲染新一帧即可,但从上面的例子知,这一点单靠定时器是无法保证的。
为此,requestAnimationFrame应运而生,其作用就是让浏览器流畅的执行动画效果。可以将其理解为专门用来实现动画效果的api,通过这个api,可以告诉浏览器某个JavaScript代码要执行动画,浏览器收到通知后,则会运行这些代码的时候进行优化,实现流畅的效果,而不再需要开发人员烦心刷新频率的问题了。

3.1 requestAnimationFrame的优势体现在
  • CPU节能:使用setTimeout实现的动画,当页面被隐藏或最小化时,setTimeout 仍然在后台执行动画任务,这完全是浪费CPU资源。而requestAnimationFrame则完全不同,当页面处理未激活的状态下,该页面的屏幕刷新任务也会被系统暂停,因此跟着系统步伐走的requestAnimationFrame也会停止渲染,当页面被激活时,动画就从上次停留的地方继续执行,有效节省了CPU开销。
  • 函数节流:在高频率事件(resize,scroll等)中,为了防止在一个刷新间隔内发生多次函数执行,使用requestAnimationFrame可保证每个刷新间隔内,函数只被执行一次,这样既能保证流畅性,也能更好的节省函数执行的开销。一个刷新间隔内函数执行多次时没有意义的,因为显示器每16.7ms刷新一次,多次绘制并不会在屏幕上体现出来。
3.2 requestAnimationFrame的使用

requestAnimationFrame的用法与setTimeout很相似,只是不需要设置时间间隔,回调函数会在浏览器重绘之前调用。它返回一个整数,表示定时器的编号,这个值可以传递给cancelAnimationFrame用于取消这个函数。

webview优化
mainfest使用
requestAnimationFrame用法
前端性能

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值