React App - Performace

起因

最近突然发现在大文件渲染预览的时候, 会卡顿很久, 连loading都无法显示, 用浏览器的performance查看, 发现是因为设置了loading之后, 会再次重排(reflow)一遍所有的子节点, 导致页面卡顿, 表现在performace记录上是会出现很长的一条Layout Shift记录

问题排查

仔细研究后发现这个问题触发的具体流程是:

  1. 打开一个比较大的页面
  2. 点击事件刷新页面数据
  3. 刷新时候触发loading动画
  4. 由于我们的loading动画在大页面的最外层, 会触发所有子节点reflow, 导致Layout Shift
  5. 子节点reflow完成后, 数据加载回来, 取消loading动画, 刷新数据
  6. 新数据再次触发reflow, 两次连续的Layout Shift导致用户感觉卡顿

解决办法

项目中的loading组件是直接使用的antdSpin组件, 而包裹页面的用法一般如下, 而且为了支持自动适配大小, 有时会设置flex相关的class, 支持内层容器自动适配外层容器大小

1
2
3
<Spin tip='Loading...'>
<Alert message='Alert message title' description='Further details about the context of this alert.' type='info' />
</Spin>

而解决重绘reflow的方法也很简单, 就是各处都讲过的: 绝对定位元素不会引起reflow, 开发一套适配spin的绝对定位的class就可以了, 将真实的子元素放在Spin外层, 就不会引起reflow

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
.ant-spin-relative {
position: relative;
.ant-spin-nested-loading {
position: static;
.ant-spin-spinning {
display: flex;
align-items: center;
justify-content: center;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
z-index: 10;
max-height: 100%;
background-color: rgba(255, 255, 255, 0.5);
}
}
}
1
2
3
4
5
6
<div className='ant-spin-relative'>
<Spin spinning={true}>
<div></div>
</Spin>
<Page />
</div>

小结

虽然最终的解决办法很简单, 但是一路排查下来过程却挺麻烦, 特别是chrome开了performance后渲染性能感觉直接减少了两倍, 十分影响效率

作者

Mosby

发布于

2020-12-10

许可协议

评论