具有大型数据集的组件仅在 IE11/Edge 上运行缓慢
Posted
技术标签:
【中文标题】具有大型数据集的组件仅在 IE11/Edge 上运行缓慢【英文标题】:Components with large datasets runs slow on IE11/Edge only 【发布时间】:2016-09-09 17:52:58 【问题描述】:考虑下面的代码。 <GridBody Rows=rows />
并想象 rows.length
将等于 2000 或更多的任何值,在此示例中每个数组大约有 8 列。我使用此代码的更扩展版本来呈现表格的一部分,该表格一直在限制我的 Web 应用程序。
var GridBody = React.createClass(
render: function ()
return <tbody>
this.props.Rows.map((row, rowKey) =>
return this.renderRow(row, rowKey);
)
</tbody>;
,
renderRow: function (row, rowKey)
return <tr key=rowKey>
row.map((col, colKey) =>
return this.renderColumn(col, colKey);
)
</tr>;
,
renderColumn: function (col, colKey)
return <td key=colKey dangerouslySetInnerhtml= __html: col ></td>;
);
现在进入实际问题。看起来计算(即使使用我自己的代码)似乎快得惊人,甚至 ReactJS 与 virtualDOM 的工作也没有问题。
但是reactJS中有这两个事件。
componentWillUpdate
直到一切正常。
然后是componentDidUpdate
,这似乎很好,而且都在 chrome 上。
问题
但是 IE11/Edge 的速度比任何其他浏览器都慢大约 4-6 秒,而使用 F12-Inspector 这似乎要慢到 8 秒比 Chrome。
我已尝试解决此问题的步骤:
去除不必要的代码。
将计算时间缩短几毫秒。
将网格拆分为松散的组件,这样 virtualDOM 就不会尝试 一次更新整个组件。
尝试将所有内容连接为字符串并允许对 只设置一次innerhtml。这实际上似乎是 IE 中的一个错误 大字符串在 IE11 上大约需要 25-30 秒。而且只有 30 毫秒 铬。
我还没有找到合适的解决方案。我在上面所做的操作似乎使 IE 中的情况变得不那么糟糕,但问题仍然存在,即“现代”或“最新”浏览器仍然慢 3-4 秒。
更糟糕的是,这似乎几乎冻结了整个浏览器并且正在渲染。
tl;dr 如何提高 IE 和其他浏览器(如果可能)的整体性能?
如果我的问题不清楚,我深表歉意,我在这件事上筋疲力尽。
edit:特别是 IE 上的 DOM 访问速度很慢,因为设置的 innerHTML 被调用超过 10.000 次。这可以在 ReactJS 中防止吗?
【问题讨论】:
如果可以覆盖渲染。你可以做的是大幅提高性能,重用行。我的意思是,如果您一次显示 10 行,则在 dom 中创建 20 行(不是整个 2000+),然后当用户滚动时,显示下一组,清除前 10 行数据并放入下一组里面的数据。详细说明该想法的参考:(尽管针对不同的库)elements.polymer-project.org/elements/iron-list。请参阅“为什么要使用尝试提高 IE 性能的方法:
检查您是否在生产模式下运行(这会删除道具验证等内容)并在适用的情况下进行 Webpack / Babel 优化
渲染页面服务器端,让 IE 没有问题(如果您的设置中支持 SS 渲染)
确保不多次调用渲染,这样的工具很有帮助:https://github.com/garbles/why-did-you-update
您为什么使用dangerouslySetInnerHTML
?如果您取出dangerouslySetInnerHTML
,它会大大加快速度吗?
为什么不根据对象数组(或传递的多维数组)自动生成行和列,我很确定 React 会以这种方式减少 DOM 交互(利用 VDOM)。 <tr>
和 <td>
将是虚拟 dom 节点。
使用https://github.com/bvaughn/react-virtualized 之类的东西来有效地呈现大型列表
【讨论】:
react-virtualized 使用与我们自己制作的几个实现相同的想法,并且它也具有我们在 IE10-11 等浏览器中看到的相同性能问题。 DangerouslySetInnerHTML 用于设置我们从结果集中获取的一些 HTML。我们已经尝试过没有这个,并且与我们的测试没有任何区别。服务器端渲染也已启用,但在重新渲染发生时会出现相同的问题。 我使用 github 分支进行了检查,但我们已经彻底消除了大多数不需要的重新渲染。但这并不是这里的特别问题。当组件必须重新渲染一个新的数据集(即推送一个新排序的数据集)时,浏览器很难跟上查找 dom 节点和设置 innerhtml 的速度。在我们代码的当前状态下,重新渲染只发生一次。 您是否尝试删除dangerouslySetInnerHTML
只是为了测试针对 IE 的性能?你说“我们已经尝试过没有这个,并且与我们的测试没有任何区别。”这是否意味着您将其作为临时措施删除了,或者您将其替换为 <tr>
和 <td>
的?
您可以仔细检查的其他事情是它是否处于生产模式,并且您已经进行了其他优化,例如使用 Babel 插件删除道具验证
嘿,谢谢马蒂。事实上,这对我们帮助很大。生产模式和开发模式之间的差异是 40-50% 的字面性能增益。我们甚至没有想到这一点。这是迈向前进道路的重要非侵入性步骤。您应该将其添加到您的答案中,以便我接受。【参考方案2】:
除了@Marty 的优点之外,运行dynaTrace 会话以查明有问题的代码。它应该让您更好地了解瓶颈在哪里。它的结果通常比 IE 开发者工具更有用。
免责声明 - 我与 dynaTrace 团队没有任何联系。
【讨论】:
我对注册更多垃圾邮件不感兴趣,抱歉。这只会帮助我找到我已经发现但没有解决方案的问题。 您的来电。不幸的是,telerik 在邮件墙后面放了一个出色的工具。【参考方案3】:在黑暗中拍摄:尝试不渲染或不显示,直到一切都完成。
让表格元素显示:在完成之前不显示 在屏幕外渲染 在一个带有隐藏溢出的小 DIV 中 甚至可以输出到一个巨大的 HTML 字符串,然后在完成后将其插入到 DOM 中。【讨论】:
将其渲染到屏幕外,将表格元素设置为 display: none 不会获得性能,因为仍然需要进行 DOM 搜索和操作。我们尝试将其放入 iframe 中,但无济于事。已经尝试输出为一个巨大的 html 字符串,这实际上比 12000+ dom 操作慢 3-8 倍。 实际上将 html 连接到一个字符串,然后进行单个 DOM 操作要快得多。由于某种原因,IE 对于 for() 循环和数组非常慢。因此点赞。以上是关于具有大型数据集的组件仅在 IE11/Edge 上运行缓慢的主要内容,如果未能解决你的问题,请参考以下文章
在具有大型数据集的 Firebase 数据库上查询非常非常慢