React 性能优化
首先性能优化界有句经典的名言,叫「Measure/Profile first, optimise second」,意思就是先分析瓶颈,再进行优化。这是推崇数据先行的思路,理由是我们从理论上推导所知的性能瓶颈,不一定是真正的问题所在,因为在我们写的代码和实际在机器上运行的代码中间,还可能有编译器或框架本身会为我们做优化,这中间过程是不可见不可预测的。因此,先做 profile,从数据上看到性能瓶颈以后再进行优化,往往是比较高效的做法。
然后,程墨在 《浅出》 中引用了 Donald 的名言:「过早优化是万恶之源」并补全了原句,指出其实过早优化非架构上的、对性能影响不大的代码才是万恶之源,对核心代码的架构和性能进行优化是合理的,并且应该时时进行,越早越好,越到后面成本越高。至于什么算核心代码,大概没人能给出明确定义,只能依靠各人经验而为了。但他这里就指出了,经验(而非数据)在优化领域还是有用武之地的。
那么,以 React 为 UI 库的代码还有什么可优化的地方?不是说 React 的 diff 算法已经非常牛逼,reconciliation 已经非常高效了么?这是因为,React 只是个库(愿意的话也可叫框架),而没有任何库能完美契合 所有 使用者的需求。这就导致,为了保证绝大多数人的正常使用,它必须使用保守的设计策略,而不能假设每个开发者都具有比较丰富的背景知识。这个正确而保守的策略就为高级开发者带来了优化的空间。那么问题来了,你,是不是(是否愿意成为)这个高级的开发者呢?
React 组件的优化策略从大面上分列如下:
- 避免不必要的 re-
render
- 定制
shouldComponentUpdate
- 数组唯一的
key
属性
- 定制
- 避免不必要的数据计算
- 纯净的副作用方案:
reselect
- 纯净的副作用方案:
避免不必要的 re-render
shouldComponentUpdate
这个方法是组件渲染前会被 React 询问的方法,如果返回 false
,则组件不会被重新渲染。能否精准地控制这个方法的返回,是提升渲染、更新性能的重要因素。那么同学可能会有疑问,我写了几个月的前端代码,我们项目也没几个地方出现 shouldComponentUpdate
方法啊,难道这就说明我们项目的代码性能都不行吗?嗯,说对了一半。
待补。
数组唯一的 key
属性
避免不必要的数据计算
使用 reselect
经过一段时间使用发现,reselect 简直是 redux 项目的标配。如果你的 mapStateToProps()
中都仅是非常简单的从 store 中挑值,那当我没说,你很大概率不需要 reselect。但假如有以下的场景,那么几乎可以肯定 reselect 会是一个很好的方案:
mapStateToProps
中存在数据计算,你需要缓存以提升性能- 增删数据结构
- 从已知数据计算状态
mapStateToProps
中存在数据结构变换,通常因为前端 view 需要的数据不是 redux 原始的数据结构- 实战场景1:章节分页
- 实战场景2:建立索引
- 需要将
mapStateToProps
封装一层,以达到 隔离组件与数据结构(redux 数据结构变化仅影响 reducer 和 selector) 或 建立统一数据获取逻辑(同一段数据获取逻辑可以被多个组件复用) 等目的
其他方案
- 在
render
中计算差异 - 这样每次可能都会重新计算。然后又需要在render
中引入memoize
- 将关联计算放在 reducer 并将算完的数据放到 redux - 这样 redux state 树会出现数据冗余。数据冗余有什么不好呢?维护一致性有成本和风险、可能不想级联修改
其他问题
用上 reselect 以后你可能会发现另一个问题,就是当你一份同样的 reducer 逻辑需要给多个组件使用时,你需要一个机制来区分。很多时候这个机制就是 const mapStateToProps = (store, ownProps) => ({})
。好,这个机制可能会有问题,因为 ownProps
可能会一直变,导致 selector 多次重复计算,失去其缓存的优势。
问题的本质在于,ownProps
共享的不只是 reducer 核心逻辑,还需要有各自独立的数据结构,而 reselect
不能提供各自独立的缓存层,它只有一层。所以不仅需要一套机制共享 reducer 逻辑,还需要另一套机制,提供互相隔绝的数据缓存层。解决方案:
- 使用返回函数的
mapStateToProps
,这也是 react-redux 提供了专门支持的 - 使用
re-reselect
参考资料
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论