React优化八股文背得头头是道,但实际操作起来却不知道从哪个地方下手?利用好React Profile的火焰图,帮你迅速找到性能瓶颈。
什么是火焰图
火焰图(Flame Graph)是一个水平着色带有时间纬度的轴,用于可视化展示该期间各分布式请求的调用以及路径。
A flame graph visualizes a distributed request trace and represents each service call that occurred during the request's execution path with a timed, color-coded, horizontal bar.
它最早是由Brendan Gregg开发用于调试优化Linux性能的指标工具。之后此概念广泛用引用于各领域、各平台中。因为它表示cpu的繁忙程度,最初的颜色标记偏暖色,且根据时间在横轴表向上堆积调用堆栈块,看起来像熊熊燃烧的火焰,火焰图因此得名。
火焰图的横纵坐标概念
虽然形式在各个工具中表现不一,火焰图始终是以一个二维向的堆栈图形标识。
X轴可理解为时间,一个调用方法横跨的横坐标越长,表示它运行的时间更长。原理是在不断的抽样数据中,此方法出现的次数越多。
Y轴由块级展示,表示方法的调用堆栈,由根节点表示的方法逐级向上调用。
概念解释太模糊我们上图看下具体的例子:
上图中,方法a作为根节点跨越了整个时间纬度。由底向上来看方法a先后调用了方法b和方法c。方法c调用了方法d。
那上图中谁占用的cpu时间最长,可优化的潜力最大呢?如果答方法a就错了,因为我们需要看每个方法的投影时长,而自身长度为方法存在的生命周期长度。假设x轴上方有个挡板,由底部打光把所有方法向上投影,所占跨度最长的应该是方法d。所以方法d才是在整个时间纬度占用cpu时间最长,可优化潜力最大的方法。
在Chrome中调试React应用
接下来就是实战,利用火焰图找到渲染占用时间比较长的模块。我们需要用到一个收集Profile信息的Chrome插件叫做React Developer Tools (github.com/facebook/re…)。安装后打开需要检查的页面,在devTools的profile一栏内录制一段时间便可得到这段时间内对应的火焰图。
得到的结果页面很多信息,我们最关注的当然是火焰图本身。
在此之前还有个更重要的点,是位于结果页右上角的时间切片总览图,插件已经根据数据结果在宏观上切分了几个时间切片:横坐标上从左到右是时间的递进;纵坐标上是该时间片在整体录制时间内的相对时长。点击对应的时间切片可以看当前时间段内的火焰图。
这个火焰图和我们上面聊到的火焰图不太一样,首先父子关系的位置是上下颠倒的,即最上面一层是根节点,逐级往下是对应的子孙节点。例如下截图的RebooApply为根节点,他包含一个子节点ReactRedux.Provider。
组件名称后面跟着的两个时间分别是自身的渲染时间和组件生命周期存在的时间,即上章节我们提到的投影长度和自身长度。Profiler也用不同的颜色给出暗示,偏暖色的模块表示渲染时间更长,而偏冷色则渲染时间较短。非着色的部分表示是在此时间片内未触发渲染,自然在此环境下也不需要去做过多分析。
如下图,TiledBill以及自身的子组件styled.div(一个styled-component)投影长度较长且颜色偏暖,开发同学可以针对此模块进一步分析是否有优化空间。
在React Native Debugger中调试React Native应用
React Native的调试和纯react应用的调试大同小异,无非使用的工具不同。RN应用默认连接Chrome进行调试,但要看火焰图需要下载React Native Debugger(github.com/facebook/re…)或者其他第三方调试工具。
通过特定端口连接好RN应用和调试工具后,录制一段时长的页面渲染,便可得到同上一章节类似的火焰图。如下:
Ranked统计天梯
常规的火焰图旁边还有一个不错的工具是天梯图(Ranked),这里每个模块的渲染时长都做了去重累积并按从大到小的顺序展示出来。如果单个模块过长,可以考虑对此模块的特定优化处理。
有了具体的统计数据可以很好得指导我们优化工作的进行。写这篇文章的我看到示例上几条高亮色的渲染时间很长的一顿脸红,别说了,打工狗继续搬砖优化去了。