前端性能优化是前端面试过程中永远逃不开的问题,尤其是针对代码量巨大的单页应用,优化更为重要。这里结合项目经历,总结一下项目中做过的性能优化。
首先,我们需要思考一下,前端出现性能问题可能有哪些层面的原因?加载速度慢?页面运行卡,动画卡顿不流畅?
所以,从用户角度来看,前端性能优化可以分为两个方面。一个是页面加载的很快,另一个是页面使用起来很流畅。因此,对性能优化的探索,我们可以分为页面加载时间跟页面运行效率两个方向来进行研究。
移动端一个h5页面,从用户点 H5 链接到页面渲染完成展示给用户,需要经历的过程,如下图:
其中 Webview 容器初始化、静态资源加载以及对后端接口的请求,耗时是比较多的,并且这个耗时页面一定处于白屏阶段,项目中通常会对这三块给出一些常规的优化方案,渲染的耗时优化本文不论述。
我们采用过业界常用的全局WebView的方式,在我们的rn首页,我们会在用户进入首页时候,就初始化一个后续资源页面的的WebView待用,并隐藏,当点击查询进入资源页面的时候,直接使用这个WebView加载对应网页,并展示。
这块涉及到的内容很多,主要是通过webpack打包机制,浏览器缓存机制,cdn加速,域名扩展等方式优化静态资源。
骨架屏也是在移动端页面首屏优化的一个重要手段,在页面数据未准备好的情况,相比与枯燥的白屏页面而言,展示骨架屏能给用户一个好的感官体验。但是如何生成质量高的骨架屏也是一个难点,需要综合考虑 ROI 来选择是否使用骨架屏。
为了保证页面运行效率,快速响应用户的交互,主要需要进行的是代码层面的优化。
通过一个例子说明:
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。
在SSR开发时,前端打包后,node后端就可以通过这个json数据,返回正确资源路径的html模板
动画是由浏览器按照一定的频率一帧一帧的绘制的,由css实现的动画的优势就是浏览器知道动画的开始及每一帧的循环间隔,能够在恰当的时间刷新UI,给用户一种流畅的体验,而js的setInterval或setTimeout实现的JavaScript动画就没有这么可靠了,因为浏览器压根就无法保证每一帧渲染的时间间隔,一般情况下,每秒平均刷新次数能够达到60帧,就能够给人流畅的体验,即每过 1000/60 毫秒渲染新一帧即可,但从上面的例子知,这一点单靠定时器是无法保证的。
为此,requestAnimationFrame应运而生,其作用就是让浏览器流畅的执行动画效果。可以将其理解为专门用来实现动画效果的api,通过这个api,可以告诉浏览器某个JavaScript代码要执行动画,浏览器收到通知后,则会运行这些代码的时候进行优化,实现流畅的效果,而不再需要开发人员烦心刷新频率的问题了。
requestAnimationFrame的用法与setTimeout很相似,只是不需要设置时间间隔,回调函数会在浏览器重绘之前调用。它返回一个整数,表示定时器的编号,这个值可以传递给cancelAnimationFrame用于取消这个函数。
webview优化
mainfest使用
requestAnimationFrame用法
前端性能