具有大型数据集的组件仅在 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。请参阅“为什么要使用 部分。希望这会有所帮助! 我们正在考虑实现类似的东西,但问题是我们希望用户能够使用 CTRL+F 在如此大的列表中进行搜索,因为这是必需的。 在这种情况下,您是否可以不只是在网格顶部或下方或列上添加搜索字段,然后在 javascript 中搜索您的数据集,而不是遍历 dom,如果在您的数据集(在 JS 中的内存中),将该项目以及周围的 10 个项目加载到 dom 中。我确实同意它会感觉不那么无缝..也许一些动画可以帮助解决这个问题。 这需要我加载整个数据集(可以超过 100 万行)才能实现相同的功能。我们目前将其限制为 2000 并使用分页。应用程序中已经存在搜索功能,但并不能真正解决 2000 个结果的性能问题。 有些疯狂;我不知道您是否可以在 Javascript 中覆盖 cntrl+f 搜索。如果是这样,您可以捕获关键事件,搜索您在内存中(但不是在 dom 中!)中保存的 2000 条记录,对吗?然后你仍然可以回收可能 100-200 个 dom 元素,同时在内存中一次保留 2k 条记录。我认为结合我的第一个和第二个答案 + 您当前如何处理加载的 2k 记录之外的搜索应该能够解决您的问题。 【参考方案1】:

尝试提高 IE 性能的方法:

检查您是否在生产模式下运行(这会删除道具验证等内容)并在适用的情况下进行 Webpack / Babel 优化

渲染页面服务器端,让 IE 没有问题(如果您的设置中支持 SS 渲染)

确保不多次调用渲染,这样的工具很有帮助:https://github.com/garbles/why-did-you-update

您为什么使用dangerouslySetInnerHTML?如果您取出dangerouslySetInnerHTML,它会大大加快速度吗? 为什么不根据对象数组(或传递的多维数组)自动生成行和列,我很确定 React 会以这种方式减少 DOM 交互(利用 VDOM)。 &lt;tr&gt;&lt;td&gt; 将是虚拟 dom 节点。

使用https://github.com/bvaughn/react-virtualized 之类的东西来有效地呈现大型列表

【讨论】:

react-virtualized 使用与我们自己制作的几个实现相同的想法,并且它也具有我们在 IE10-11 等浏览器中看到的相同性能问题。 DangerouslySetInnerHTML 用于设置我们从结果集中获取的一些 HTML。我们已经尝试过没有这个,并且与我们的测试没有任何区别。服务器端渲染也已启用,但在重新渲染发生时会出现相同的问题。 我使用 github 分支进行了检查,但我们已经彻底消除了大多数不需要的重新渲染。但这并不是这里的特别问题。当组件必须重新渲染一个新的数据集(即推送一个新排序的数据集)时,浏览器很难跟上查找 dom 节点和设置 innerhtml 的速度。在我们代码的当前状态下,重新渲染只发生一次。 您是否尝试删除 dangerouslySetInnerHTML 只是为了测试针对 IE 的性能?你说“我们已经尝试过没有这个,并且与我们的测试没有任何区别。”这是否意味着您将其作为临时措施删除了,或者您将其替换为 &lt;tr&gt;&lt;td&gt; 的? 您可以仔细检查的其他事情是它是否处于生产模式,并且您已经进行了其他优化,例如使用 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 上运行缓慢的主要内容,如果未能解决你的问题,请参考以下文章

具有大型数据集的 SQL Server 中的数据透视表

在具有大型数据集的 Firebase 数据库上查询非常非常慢

具有大型(70,000+ 项)数据集的高效 jQuery 实时搜索

R:具有 2 个大型数据集的模式匹配金融时间序列数据:

带有大型数据集的 SQL 插入

除了数据 url 之外,如何让伪元素上的剪辑路径 SVG 在 IE11/Edge 中工作?