React vs Angular:使用React缓慢渲染

我正在对Angular和React进行比较,并决定尝试一个性能testing,看看在这两个框架中,一个大的(ish)列表将会呈现多快。

当我用我的React原型和一些基本货币格式化完成后,在我的快速笔记本电脑上渲染需要2秒钟。 有了Angular,它几乎没有引人注意 – 只有当我切换到我的手机,它有一个明显的滞后。

这是非常令人惊讶的,因为有人告诉我说,React本来就是为了performance而摔打Angular的裤子,但在这种情况下,情况恰恰相反。

我将我的原型提取到一个非常简单的应用程序,试图找出问题: https : //github.com/pselden/react-render-test

在这个例子中,在改变语言之后,这个简单的列表花费了将近200ms,而我几乎没有做任何事情。

我在这里做错了什么?

/** @jsx React.DOM */ 'use strict'; var React = require('react'), Numbers = require('./Numbers'); var numbers = [] for(var i = 0; i < 2000; ++i){ numbers.push(i); } var App = React.createClass({ getInitialState: function() { return { locale: 'en-US' }; }, _onChangeLocale: function(event) { this.setState({locale: event.target.value}); }, render: function() { var currentLocale = this.state.locale; return ( <div> <select onChange={this._onChangeLocale}> <option value="en-US">English</option> <option value="fr-FR">French</option> </select> <Numbers numbers={numbers} locales={[currentLocale]} /> </div> ); } }); module.exports = App; 
 /** @jsx React.DOM */ 'use strict'; var React = require('react'), ReactIntlMixin = require('react-intl'); var Numbers = React.createClass({ mixins: [ReactIntlMixin], getInitialState: function() { return { numbers: this.props.numbers }; }, render: function() { var self = this; var list = this.state.numbers.map(function(number){ return <li key={number}>{number} - {self.formatNumber(number, {style: 'currency', currency: 'USD'})}</li> }); return <ul>{list}</ul>; } }); module.exports = Numbers; 

PS:增加了一个angular度版本: https : //github.com/pselden/angular-render-test

编辑:我用react-intl打开了一个问题,我们调查了一下,发现使用https://github.com/yahoo/react-intl/issues/27没有那么多的开销 – 这只是React本身的慢这里。

这绝对是一个有趣的testing案例。

如果你看看时间线,你可以看到Angular在20ms内完成了处理变化事件。 剩下的时间用于布局和重绘。

有角的时间线

反应(使用生产版本,你的回购默认使用开发)大约需要59ms。 再次,其余的时间花在布局和重绘。

反应时间表

如果你看看CPU的火焰图表,你可以看到Angular似乎做了很less的工作。

angular度:

有角度的CPU图形

阵营:

反应CPU图

React以shouldComponentUpdate的forms提供了一个非常好的优化钩子,当数以千计的组件中的一个实例应该更新并且其他应该保持不变时,它尤其有用。 这是一个我在这个演示中使用的技术(在隐身窗口中试用;我发现一些Chrome扩展使得布局/重绘时间更高 – 对于我来说,一旦列表长度为1000,添加/移除单个元素需要13ms,改变元素的大小/颜色需要〜1ms)。 但是,当每个元素都需要更新时,这并没有好处。

我的猜测是Angular在更改表中大部分或全部元素的时候会更快,而且在使用shouldComponentUpdate时,React会更新select的条目。

我很惊讶没有人提到PureRenderMixin 。 它实现了shouldComponentUpdate所以你不必担心它。

另外,我不知道React 性能工具是否会变得有用?

看到Ryan Florence的演讲之后,我很惊讶Angular比React更快。

我们试图分析一下我们框架的一些属性,当然这不是整个列表。 在我们看来,下面是一个统一而重要的表格,用来比较属性。

在这里输入图像说明

让我们来更多的细节:

在这里输入图像说明

在这里输入图像说明

虽然Angular与React的差异很多,但是他们可以做同样的事情,即构build客户端界面。 两者都有自己的位置。 对于那些喜欢网页开发的人来说,最重要的是创新的AngularJS的HTML方法。

AngularJS实际上是一个完整的框架,而不仅仅是一个库,就像ReactJS一样,但是通过实现虚拟DOM,ReactJS比AngularJS有更好的性能。 在我们看来,你应该使用AngularJS,如果:

  • 你打算在开发过程中进行大量的unit testing,
  • 你想为你的应用程序提供全面的解决scheme

然而,双向数据绑定经常被吹捧为使用AngularJS的优势,但是由于它是通过一系列的摘要来实现的,因此为某些函数和expression式添加太多的复杂性会导致应用程序的性能下降。

在这种特殊情况下,你需要知道状态下滑,DOM更新也是如此。 你想要做的是创build一个价格组件,它将语言环境存储在自己的状态,并接收信号(即通道或通量)来改变语言环境,而不是一直向下发送语言环境。 这个想法是,你不需要更新整个数字组件,只是里面的价格。 该组件可能如下所示:

 var Price = React.createClass({ mixins: [ReactIntlMixin], componentDidMount: function() { subscribeToLocal(this.onLocaleChange); }, onLocaleChange: function(newLocales) { this.setState({locales: newLocales}); }, render: function() { return <span>this.formatNumber(this.props.number, this.state.locales, {style: 'currency', currency: 'USD'})</span> } }); 

在React组件中,一旦你调用setState,它将立即触发渲染函数。 React会将这个组件标记为脏,并且会重新渲染这个组件内的所有子元素。

由于虚拟DOM,它不会呈现整个Native DOM元素,因此它仍然会创build其子ReactElements的新实例,这可能导致额外的Javascript内存成本。

为了避免这个问题,你需要在Component类中实现的shouldComponentUpdate函数。 它会在Render方法之前执行。 如果你发现现在没有什么改变,例如在你的例子中,你改变了state.locale。 你绝对可以认为这个组件不需要更新。 所以只需返回false来防止呈现调用。

这是解决React性能问题的基础解决scheme。 尝试在您的Numbers组件中添加“shoudlComponentUpdate”以避免吨

  • 元素重新呈现
  • 这是一个例子,所有的变化是一个数据输出。 Angular的双向数据绑定仅仅提供了一个更快的重新渲染,当所有的变化都是绑定数据的显示时,这并不是不可能的。

    在任何情况下,React都不承诺它的渲染比任何其他框架都快。 它提供的function是能够以非常有效的方式处理任意复杂的DOM更新,并提供各种生命周期方法(例如,componentWillReceiveProps,componentDidUpdate,除了上述的shouldComponentUpdate之外),以允许您触发这些事件的callback,控制如何以及如果他们应该发生。 在这里,有很less的优化,因为你正在做的是改变2000文本显示。

    编辑:为了澄清,React在进行更复杂的DOM操作时非常有用,因为它是虚拟DOMalgorithm,允许它select更新DOM所需的最小DOM操作集。 当所有需要发生的事情是2000个文本改变的实例时,仍然有很多工作要做。