小白对于前端性能优化知识点的碎片化,一旦需要运用到实际的项目中就头大~所以为了解决这个问题,整理出一套完整的性能优化方案体系:包含测量工具,项目指标,以及对应的优化点逐个攻破,这也是我在项目中用到涉及的知识点
1.优化大纲方向
2.性能优化指标和测量工具
性能优化的目的:提高用户留存率=> 提高网站的转化率
过程我们以b站的手机端作为测试站点:
2.1 network
请求瀑布图:
横向看:具体资源
纵向看:资源是串行还是并行,查看资源是否阻塞
横向看:
1.是资源下载优先级的排队等候时间,
2是请求发出去到资源回来的时间TTFB(影响原因:服务器处理能力,网络情况)
3.是资源下载的时间
2.2 lighthouse
每次生成的结果不一定相同,多次看平均即可
解析其中重要的参数:
1. First Contentful Paint:首次内容绘制,首屏开始时间
2.Speed Index:指数,标准0~3.4为fast ;3.4~5.8是中等moderate,5.8+是慢slow
3.Largest Contentful Paint:最大内容绘制 ,在渲染过程中会可能被更新,标准是0~2.5~4
更多具体指标的内容这里就不细说了,自己下去可以研究看看。
需要明白FP,FCP,LCP,DCL,L意义哟~
优化建议:
以上的解决方案:比如移除没有用上的js,css和减少阻塞资源等等,但是实际上还是要根据自己的实际业务以及取舍。比如一开始js虽然没有用上,但是想初始化加载,执行某个事件就马上响应等等。
2.3 了解帧数
对于肉眼来说,视觉流畅的帧数是1s/60fps
控制台:commamd+shift+p => frame => 有fps相关的点击即可,可查看每一个步骤的fps变化
2.4 RAIL测量模型
量化指标,提示优化方案。在实际的开发过程中只能尽量往这些指标上靠近
RAIL:R为response响应 A为animation动画 I为Idle空闲 L为load加载
R:处理事件50ms以内,超过50ms为长任务
A:1s/60fps
I:尽可能的增加空闲时间,来及时响应用户的操作(计算相关让后端完成)
L:在5s以内完成所以内容加载并且可以交互
2.5 performance
性能api:
2.6 web标准APIs
- 关键时间节点(performance)
- 网络状态:Navigator.connection
- 网页显示状态:document.webkitHidden
3.渲染优化
可看文档:developers.google.cn/web/fundame…
3.1 浏览器html渲染原理
浏览器如何解析html,css,js这些文件,并且显示到屏幕上这个过程关键渲染路径
js=> Style => layout => paint => composite(composite该步骤不在主线程)
步骤:
1.构建dom树
2.构建cssom:解析css文件
3.构建render树(dom+cssom)
4.layout:布局宽高,几何属性,比如空间大小或者在屏幕上的位置。将display:none的元素删除等等
5.paint:填充像素,它涉及绘出文本、颜色、图像、边框和阴影,绘制可能出现多个图层。比如:z-index
6.合成:由于页面的各部分可能被绘制到多层,由此它们需要按正确顺序绘制到屏幕上,以便正确渲染页面
以上布局和绘制是最消耗性能的,而且对于他们分别涉及到两个概念回流和重绘
3.2 可优化渲染环节和方法
3.2.1 回流和重绘
回流:几何属性变化,触发layout;添加删除元素/display:none/移动元素/修改字体大小等
重回:不影响几何属性,比如颜色等
注意:回流一定会触发重绘,而重绘不一定会回流
减少回流优化:
-
transform,opacity
-
批量处理回流(主流框架),js赋值class name
-
避免设置多层内联样式,写个外部类这样只回流一次
-
让可能需要多次回流的元素脱离文档流
-
减少布局抖动,不要在循环内获取dom 的样式。实现读写分离
-
不使用table
-
避免强制同步布局:应该先计算样式再布局
3.2.2 复合线程和图层
复合线程:就是将页面拆分成多个图层绘制再进行复合
拆分规则:浏览器规则,transform,opacity
3.2.3 raF
h5新增的api,为了解决settimeout刷新频率不稳定的原因。
raf在布局和绘制之前发生
window.requestAnimationFrame()由系统来决定调用回调函数的执行时机,回调函数执行次数通常与浏览器屏幕刷新次数相匹配
raf通常是1s/60hz,过快的频率超过用户所见或者浏览器能显示。比如:1s改变样式1000次。raf减少无用执行
demo: 1000个box元素,滑动鼠标修改宽度卡顿问题优化,
<script type="text/javascript">
var lock = false
window.addEventListener('pointermove', (e) => {
let pos = e.clientX
if(lock) return
lock = true
const list = document.getElementsByClassName('box')
window.requestAnimationFrame(() => {
for(var i=0;i<list.length;i++){
list[i].style.width = pos+ 'px'
}
lock = false
})
})
</script>
取消:cancleAnimationFrame()
3.2.4 rIC
方法将在浏览器的空闲时段内调用的函数排队,目的是让我们把一些计算量较大但是又没那么紧急的任务放到空闲时间去执行。将任务细小话,分割成不同大小的任务。在每一帧结束之后,如果还有空闲时间,那么浏览器会分一部分的空闲时间去完成部分任务,当前前提是浏览器会保留大部分的空闲时间去随时准备接收用户的事件。
window.requestIdleCallback(() => {
console.log('kongxian');
})