React高级性能优化
作者:hepeguo 发布时间:[ 2016/8/16 16:12:13 ] 推荐标签:软件测试 性能测试
Immutable-js 和 Flux
如果你在使用 Flux,你应该开始使用 immutable-js 写你的 stores,看一下 full API。
让我们看一个可行的方式,使用不可变数据结构来给消息示例创建数据结构。首先我们要给每个要建模的实体定义一个 Record。Records 仅仅是一个不可变容器,里面保存一系列具体数据:
var User = Immutable.Record({
id: undefined,
name: undefined,
email: undefined
});
var Message = Immutable.Record({
timestamp: new Date(),
sender: undefined,
text: ''
});
Record 方法接收一个对象,来定义字段和对应的默认数据。
消息的 store 可以使用两个 list 来跟踪 users 和 messages:
this.users = Immutable.List();
this.messages = Immutable.List();
实现函数处理每个 payload 类型应该是比较简单的,比如,当 store 看到一个代表新消息的 payload 时,我们创建一个新的 record,并放入消息列表:
this.messages = this.messages.push(new Message({
timestamp: payload.timestamp,
sender: payload.sender,
text: payload.text
});
注意:因为数据结构不可变,我们需要把 push 方法的结果赋给 this.messages。
在 React 里,如果我们也使用 immutable-js 数据结构来保存组件的 state,我门可以把 PureRenderMixin 混入到我门所有的组件来缩短重新渲染回路。当大家考虑在项目中使用 React 的时候,第一个问题往往是他们的应用的速度和响应是否能和非 React 版一样,每当状态改变的时候重新渲染组件的整个子树,让大家怀疑这会不会对性能造成负面影响。React 用了一些黑科技来减少 UI 更新需要的花费较大的 DOM 操作。
使用 production 版本
如果你在你的 React app 中进行性能测试或在寻找性能问题,一定要确定你在使用 minified production build。开发者版本包括额外的警告信息,这对你在开发你的 app 的时候很有用,但是因为要进行额外的处理,所以它也会比较慢。
避免更新 DOM
React 使用虚拟 DOM,它是在浏览器中的 DOM 子树的渲染描述,这个平行的描述让 React 避免创建和操作 DOM 节点,这些远比操作一个 JavaScript 对象慢。当一个组件的 props 或 state 改变,React 会构造一个新的虚拟 DOM 和旧的进行对比来决定真实 DOM 更新的必要性,只有在它们不相等的时候,React 才会使用尽量少的改动更新 DOM。
在此之上,React 提供了生命周期函数 shouldComponentUpdate,在重新渲染机制回路(虚拟 DOM 对比和 DOM 更新)之前会被触发,赋予开发者跳过这个过程的能力。这个函数默认返回 true,让 React 执行更新。
shouldComponentUpdate: function(nextProps, nextState) {
return true;
}
一定要记住,React 会非常频繁的调用这个函数,所以要确保它的执行速度够快。
假如你有个带有多个对话的消息应用,如果只有一个对话发生改变,如果我们在 ChatThread 组件执行 shouldComponentUpdate,React 可以跳过其他对话的重新渲染步骤。
shouldComponentUpdate: function(nextProps, nextState) {
// TODO: return whether or not current chat thread is
// different to former one.
}
因此,总的说,React 通过让用户使用 shouldComponentUpdate 减短重新渲染回路,避免进行昂贵的更新 DOM 子树的操作,而且这些必要的更新,需要对比虚拟 DOM。
shouldComponentUpdate 实战
这里有个组件的子树,每一个都指明了 shouldComponentUpdate 返回值和虚拟 DOM 是否相等,后,圆圈的颜色表示组件是否需要更新。
在上面的示例中,因为 C2 的 shouldComponentUpdate 返回 false,React 不需要生成新的虚拟 DOM,也不需要更新 DOM,注意 React 甚至不需要调用 C4 和 C5 的 shouldComponentUpdate。
C1 和 C3 的 shouldComponentUpdate 返回 true,所以 React 需要向下到叶子节点检查它们,C6 返回 true,因为虚拟 DOM 不相等,需要更新 DOM。后感兴趣的是 C8,对于这个节点,React 需要计算虚拟 DOM,但是因为它和旧的相等,所以不需要更新 DOM。
注意 React 只需要对 C6 进行 DOM 转换,这是必须的。对于 C8,通过虚拟 DOM 的对比确定它是不需要的,C2 的子树和 C7,它们甚至不需要计算虚拟 DOM,因为 shouldComponentUpdate。
那么,我们怎么实现 shouldComponentUpdate 呢?比如说你有一个组件仅仅渲染一个字符串:
React.createClass({
propTypes: {
value: React.PropTypes.string.isRequired
},
render: function() {
return <div>{this.props.value}</div>;
}
});
我们可以简单的实现 shouldComponentUpdate 如下:
shouldComponentUpdate: function(nextProps, nextState) {
return this.props.value !== nextProps.value;
}
非常好!处理这样简单结构的 props/state 很简单,我门甚至可以归纳出一个基于浅对比的实现,然后把它 Mixin 到组件中。实际上 React 已经提供了这样的实现: PureRenderMixin
但是如果你的组件的 props 或者 state 是可变的数据结构呢?比如说,组件接收的 prop 不是一个像 'bar' 这样的字符串,而是一个包涵字符串的 JavaScript 对象,比如 { foo: 'bar' }:
React.createClass({
propTypes: {
value: React.PropTypes.object.isRequired
},
render: function() {
return <div>{this.props.value.foo}</div>;
}
});
前面的 shouldComponentUpdate 实现不会一直和我们期望的一样工作:
// assume this.props.value is { foo: 'bar' }
// assume nextProps.value is { foo: 'bar' },
// but this reference is different to this.props.value
this.props.value !== nextProps.value; // true
这个问题是当 prop 没有改变的时候 shouldComponentUpdate 也会返回 true。为了解决这个问题,我们有了这个替代实现:
shouldComponentUpdate: function(nextProps, nextState) {
return this.props.value.foo !== nextProps.value.foo;
}
本文内容不用于商业目的,如涉及知识产权问题,请权利人联系SPASVO小编(021-61079698-8054),我们将立即处理,马上删除。
相关推荐
更新发布
功能测试和接口测试的区别
2023/3/23 14:23:39如何写好测试用例文档
2023/3/22 16:17:39常用的选择回归测试的方式有哪些?
2022/6/14 16:14:27测试流程中需要重点把关几个过程?
2021/10/18 15:37:44性能测试的七种方法
2021/9/17 15:19:29全链路压测优化思路
2021/9/14 15:42:25性能测试流程浅谈
2021/5/28 17:25:47常见的APP性能测试指标
2021/5/8 17:01:11热门文章
常见的移动App Bug??崩溃的测试用例设计如何用Jmeter做压力测试QC使用说明APP压力测试入门教程移动app测试中的主要问题jenkins+testng+ant+webdriver持续集成测试使用JMeter进行HTTP负载测试Selenium 2.0 WebDriver 使用指南