记一次前端性能调优——火焰图实践
问题记录
在 Antd
树组件中,通过点击向后端接口请求数据,最后渲染在页面的过程十分漫长,产品体验不佳。
分析过程
查看接口调用,返回数据条目 1w+
,耗时 600 ms
。但是实际从请求开始到渲染出树组件耗时大约是 6s
。猜测是前端渲染过程使用大量资源和时间,最终使其呈现在页面上的过程很漫长。
到了这一步,如何优化?
直接看代码根本看不出结果,这个渲染是使用 Antd
树组件进行的,这个时候通常我们就要甩锅给 antd
组件库了(谢谢蚂蚁大佬帮我背锅😄)。
但是甩锅给组件库解决不了问题。正常情况下, 1w+
的数目远远达不到需要 6s
的加载时间这种情况。因此我们需要了解此次渲染的代码执行过程。这就需要祭出浏览器的 performance
工具了。
火焰图实践
- 很简单,点击白点就可以进行录制了。
2. 进行需要观测的操作后,点击结束按钮
stop
- 最后我们可以通过生成的图片进行分析。
可以看到,在 Network
一栏中此接口请求了一个node
接口,这个接口很快就返回了。
在 main
一栏中可以看到,请求接口后进行了一个 Task
,这就是 js
中常说的宏任务了,这个宏任务下主要是执行 microtasks
,就是所谓的微任务。这个微任务由一个匿名函 anonymouse
组成,这下我们清楚了,那么这个匿名函数是什么?
由 Xt
和 set
组成,点击 set
任务,就可以看到整个 set
是哪里调用的。可以看到这个set是 mobx
库的函数,大致这个任务是 mobx
在执行数据标记。
同时在开发环境下点击 anonymouse
函数,可以很清楚的看到代码中是哪里调用的此次微任务。
现在大致清楚了,是一个微任务中的使用 mobx
相关代码造成了这次前端性能瓶颈。
- 现在我们需要把目标精确到某个语句。使用
perfermance.now()
//...
const t0 = perfermance.now()
store.tree = data
const t1 = perfermance.now()
console.log(t1 -t0) // 60000
//...
最后通过定位将此处代码找出来了。就是使用 mobx
定义的观察者,一瞬间接纳大量数据造成的。
发现是使用 mobx
造成的性能瓶颈,立刻就有三个方向可以进行了:
- 优化
mobx
性能。 - 替换使用的技术栈。
- 替换状态管理方式。
根据 mobx
官网上的优化条例,好像不太适合在这个场景下,返回的树组件是一整个数据结构,我们无法将其进行拆分。可能能进行延迟设置,比如精确找到更新的数据,然后赋值。但这样做的成本太高了,果断放弃。
替换使用的技术栈。目前好像就是 redux
, redux
在性能上和 mobx
比较没有很大的优势,而且一个项目也不允许有两种状态管理方式,果断放弃。
因此我们只能替换状态管理方式。那用什么状态管理方式,在 react
很明显是使用 react hooks
。即使用useState()
//...
cosnt [tree, setTree] = React.useState([])
//...
// store.tree = data
setTree(data)
//...
//...
优化结果
最后的结果也是不负众望,渲染效率提升了三倍,同一个接口返回后,渲染时间从 6s
缩短至 2s
。
总结
- 性能优化只是背诵各种网上的优化手段只能是应试的。最终在生产中可以通过掌握火焰图来灵活地优化前端性能。然后通过
perfermance.now()
精确到性能消耗最大的语句中。可以很明确地找到需要优化的语句。 mobx
在渲染数据时会给每条数据打上跟踪标记,为数据变化时渲染做预备,在数据量大的情况下需要消耗大量资源,这个时候可以将mobx
替换成hooks state
作为性能优化手段之一。
转载自:https://juejin.cn/post/7225975883617239101