性能优化是每个公司每个开发人员都会做的事情。性能优化是指通过各种手段,提高应用程序的响应速度、吞吐量、资源利用率等性能指标,从而提高用户体验和系统效率。
性能优化是软件开发过程中非常重要的一环。需要注意的是,性能优化需要根据具体应用场景和需求进行,不能一概而论。同时,性能优化也需要进行平衡,不能只追求单一指标的提升,而忽略其他指标的影响。例如,为了提高响应速度,可能会牺牲系统的可靠性和安全性,因此需要进行综合考虑和权衡。
今天我们就简单谈一谈前端性能优化那点事。
我们要有一个共识。
首先,性能优化不能盲目,一定是问题导向的,一定是哪里有问题,我们才去优化哪里。
其次,性能优化要遵循二八原则,用20%的精力来解决80%的问题。
再次,性能优化要有数据支撑,否则无法反馈我们优化的成果。
最后,这个过程是可以持续重复的。
前端去做性能优化一般是从两个方面来做。 网络优化和渲染优化。
性能指标
而前端的性能指标每个公司可能不太一样,我司用的比较多的是FST(first-screen-time)首屏时间。首屏时间是衡量用户体验的一个重要指标。
这个指标的采集策略大概是这样的
Part1 首屏DOM时间:
- 使用 MutationObserver 监听 document 下的 DOM 变化 (添加或删除子孙节点)
-
在 callback 方法中,筛选并记录每次 mutation 时有效的新增节点 addedNodes 及其对应的时间点 performance.now(),
push 到队列 mutationRecords 中,每个元素均为下面这种格式的一个对象 { nodes: addedNodes, startTime: startTime }
-
在 callback 方法中,还会判断是否要停止mutation 监听。目前有两个停止mutation 监听的场景:
- 通过该次 mutation 的 addedNodes 的 getBoundingClientRect 方法,与屏幕尺寸做对比,判断是否为首屏外的变更。
当监测到超过 15 次首屏外变更时,停止监听
-
通过 setTimeout 设置定时器,3s 内没有再发生 mutation 时停止监听
- 通过该次 mutation 的 addedNodes 的 getBoundingClientRect 方法,与屏幕尺寸做对比,判断是否为首屏外的变更。
-
停止监听后,开始对记录到的 mutationRecords 做处理。遍历 mutationRecords,筛选每一条记录的 nodes 中的有效首屏节点,
并计算这些节点的权重和 score,push 到队列 validRecords 中,每个元素均为下面这种格式的一个对象 { score, startTime }
-
通过 validRecords 计算最后的 DOM 首屏时间。取队列中最后一个 score 大于阈值 3 的时间,若均小于3,则取 score 最大值的时间
Part2 首屏图片时间:
- 通过 performance.getEntriesByType('resource') 拿到图片资源的请求性能数据
- 计算首屏内图片最后加载完成的时间
- 比较首屏图片时间和首屏DOM时间,取更大的值作为最终的 FST 时间
技术方案细节
- 算法的起始时间点是如何获取的?
在监听到 DOM 变化时,算法通过执行 performance.now() 获取到从页面开始加载到这次 DOM 变化所经历的时间。
可以认为 performance.now() 的结果约为 Date.now() - performance.timing.navigationStart。
-
MutationObserver 监听了什么内容?
当设置了childList 和 subtree均为true时,将监听document节点下所有的添加节点和删除节点变化。
-
start 方法执行前的mutation怎么收集?
在预采集模块中同样创建了一个MutationObserver,负责收集预采集模块之后,start方法执行之前的mutation记录。
start方法开始执行后,将关闭该MutationObserver,并率先处理之前收集到的mutation记录。
-
怎么筛选有效的mutation?怎么筛选mutation.addedNodes中的有效节点?
通过mutation发生的目标的nodeName(mutation.target.nodeName),排除非视觉元素变更。另外排除没有添加节点(addedNodes)的mutation。
通过addedNodes中每个节点的nodeName属性排除非视觉元素及iframe元素。另外还支持业务手动添加owl-ignore属性排除指定元素。
-
停止MutationObserver监听的条件是什么?
- MutationObserver上一次监听到DOM变化3s内没有再监听到新的DOM变化
- 检测到有效的首屏外节点超过15次。使用getBoundingClientRect方法拿到节点的位置信息,通过与屏幕尺寸做对比来判断是否在首屏内。
这个是大概的FST的获取逻辑,代码就不付了。收集到这些首屏时间,就需要进行一些分析。一般来说,我们会去p90或者p95的数值来做参考,目的是为了过滤掉一些极端用户场景。同时也会看1s内打开首屏的用户的占比。
流失率与首屏展现的时间的关系大家应该都明白,根据一些研究数据显示,如果页面的首屏展现时间超过3秒,那么用户的流失率就会显著增加。例如,如果页面的首屏展现时间为5秒,那么用户的流失率可能会达到30%以上。而如果页面的首屏展现时间能够控制在1-2秒之内,那么用户的流失率就会大大降低。
除了FST以外,还有很多时间指标
- 首字节时间
- DOM构建完成时间
- DOM Ready 时间
- 页面完全加载时间
这些都可以从Navigation Timing API接口中获取到。加上FST 这五个 指标足够我们分析了。
今天先写到这吧。。。。。。下一篇继续
文章评论