性能优化---effects里面调用太多次reducer导致的卡顿
背景:一个弹框,打开的时候调用了20多个接口获取一堆数据(无语),然后每个接口获取的数据,都放在model里,页面从model的store里拿数据出来渲染。导致非常非常的卡顿,一个弹框打开大概要30多秒才加载完,究其原因,还是因为触发的action太多,导致reducer在不断的修改state,
项目里面,一个model里面写了86个reducer。炸了,写这么多reducer。
如果触发的action太多,会导致reducer阶段
用谷歌浏览器看下性能,如下,一个弹框打开,光ji执行就花了37s中,简直吓死个人。说明reducer太多,并且触发的action也很多,导致每触发一个action就遍历一遍reducer,这对性能的消耗是非常恐怖的,毕竟86个reducer。

在解决问题前,先在本地打开源错误检查。

这样就可以在开发者工具中通过性能分析工具定位具体是哪个文件,如下。

红色就是卡顿的点。

解决方法:
1.发现modal弹框里面有很多的值都可以放到自己的state里面,不必放到model里,只有弹框自己用到了这些变量。把在点击表格阶段触发的接口,全部放到modal的componentDidmount里面,在callback里面setState,(这里其实可以不用model的effect去调用接口,直接调用接口也可以。)如下。

这样修改后,明显感觉速度快了很多,打开性能看看,变成19s了

2.减少请求中的action的请求次数,将多个action变成一个
因为每次yield都会更新一次整个state,并且等待更新完成后,再执行下一个yield,而四五个yield会造成渲染重复浪费.
细心的再查看调用的接口发现,有一个副作用,里面至少调用了5次reducer,如下,

而这些reducer执行有没有什么先后关联,所以可以把他们都放在一个action里面进行派发,如下

reducer简单的进行修改即可。

再看看性能

瞬间又快了很多,变成12s了。
3.去掉loading。(在我们这个项目中)
还是刚刚那个接口,如下,这里还调用了两次reducer,是改变表格loading的。。。就是给一个加载动画的。

这里完全没必要这样做,使用dva自己的全局loading即可。这里还有个问题:使用全局loading,要放在当前组件最顶级的index.js里面,不要放在又在modal里绑定loading,这样的话,等于白修改了。
这样改之后,又快了一点点。。。

4.需要重model里面取值,只需要关联那一个字段即可,不要全部都connect进来
发现有一个字段要从公共的model里面取,但是整个modal.js确把整个common全部connect进来了。

改成这样,把要取的字段(这种取字段的方法慎用,貌似会造成卡顿,可以测试一下)

这样拿出来即可。
最好再改一下,把它放到最顶级的index.js里。

所有的值都从父组件获取,包括dispatch,
用组件传值的方式拿过来即可。遵守connect的规则,只连接当前组件最顶级的index.js,它的子组件,通过props进行通信。这样又可以节省一大笔性能开销。
最终效果
最后在线上看变成7s了。之前差不多要20s的(注:上面性能的截图都是在本地程序运行时截的,发现本地运行比线上运行至少要慢两倍,下面的这张截图就是在线上查看的)


js执行时间从22s变成了8s了。优化的还可以。肯定还有再进一步优化的可能。
这个弹框的一些数据,
整个modal.js 有 2234行代码,
model里面有 1900行代码。。。。。。然后在加上打开弹窗要调用20多个接口去拿数据。要真正的优化感觉只能重构了。
最后总结:出现这么大的延迟问题,完全就是开发的人,不懂dva, model的基本使用,react的数据流向原则,乱连接,乱connect造成的。跟框架一点关系都没得。。。。果然,开发中遇到的大部分性能问题都是自己业务没写好,要不就是没用来。
参考:
浙公网安备 33010602011771号