【问题标题】:Possible to add large amount of DOM nodes without browser choking?可以添加大量 DOM 节点而不会导致浏览器阻塞吗?
【发布时间】:2010-09-30 13:26:35
【问题描述】:

我的网站上有一个显示表格的网页,每 10 秒重新加载一次 XML 源数据(使用 XmlHttpRequest),然后更新表格以向用户显示数据的任何添加或删除。为此,JavaScript 函数首先清除表中的所有元素,然后为每个数据单元添加一个新行。

最近,我在 Internet Explorer 中解决了由 DOM 销毁和创建代码引起的一些内存泄漏问题(其中大部分与 JavaScript 对象和 DOM 对象之间的循环引用以及我们正在使用的 JavaScript 库有关悄悄地保持对使用new Element(...) 创建的每个 JS 对象的引用,直到页面被卸载)。

解决了内存问题后,我们现在发现了一个基于 CPU 的问题:当用户有大量数据要查看时(100+ 个数据单元,这等于要创建 100 个<tr> 节点,加上所有每列的表格单元格),该进程占用 CPU,直到 Internet Explorer 提示用户:

停止运行此脚本?
此页面上的脚本导致 Internet Explorer 运行缓慢。 如果它继续运行,您的计算机可能会变成 没有反应。

似乎运行行和单元格创建代码乘以 100 多条数据是导致 CPU 使用率飙升的原因,该函数运行时间“太长”(从 IE 的角度来看),从而导致IE 为用户生成此警告。我还注意到,虽然“更新屏幕”功能针对 100 行运行,但 IE 不会重新呈现表格内容,直到该功能完成(因为 JS 解释器在该时间段内使用 100% CPU,我假设) .

所以我的问题是:在 JavaScript 中有没有办法告诉浏览器暂停 JS 执行并重新渲染 DOM?如果没有,是否有任何策略来处理创建大量 DOM 节点并且 让浏览器阻塞?

我能想到的一种方法是异步处理“更新表”逻辑;也就是说,一旦完成重新加载 XML 数据的 Ajax 方法,将数据放入某种数组中,然后设置一个函数(使用setInterval())运行,该函数一次处理一个数组元素。然而,这似乎有点像在 JavaScript 环境中重新创建线程,这似乎会变得非常复杂(即,如果在我仍在重新创建表的 DOM 节点时触发另一个 Ajax 数据请求怎么办?等等)


更新:只是想解释一下我为什么接受 RoBurg 的回答。在进行一些测试时,我发现我的框架中的new Element() 方法(我正在使用mootools)比IE7 中的传统document.createElement() 慢大约2 倍。我跑了一个测试,创建1000个<spans>并将它们添加到<div>,在IE7上使用new Element()大约需要1800ms(在Virtual PC上运行),传统方法大约需要800ms。

我的测试还揭示了一种更快的方法,至少对于像我这样的简单测试:使用DocumentFragments as described by John Resig。使用 IE7 在同一台机器上运行相同的测试需要 247 毫秒,比我原来的方法提高了 9 倍

【问题讨论】:

    标签: javascript ajax dom


    【解决方案1】:

    避免使用一个大的for 循环在一大步中渲染所有数据。而是将数据分解成更小的块。

    使用while 循环渲染每个较小的块。在该块完成后,使用setTimeout [time 1ms] 调用下一个块,让浏览器“喘口气”。

    您可以完全避免使用while 循环,而只使用setTimeout

    使用setTimeout 技术稍微减慢执行速度,但您不应该收到警告消息。

    要注意的另一件事是不要将每个元素单独附加到文档中。考虑创建一个新的tbody,将新行附加到新的tbody,并将tbody 附加到表中。

    还有很多其他因素会导致应用程序缓慢。将它们全部冲洗掉会很有趣。

    这里对警告进行了巧妙的研究:http://ajaxian.com/archives/what-causes-the-long-running-script-warning

    【讨论】:

      【解决方案2】:

      您可以 cloneNode(false) 要重复的元素,然后将其用于循环,而不是每次都生成元素。

      【讨论】:

        【解决方案3】:

        100 个<tr> 并没有那么多...你还在使用那个框架的new Element() 吗?这可能是它的原因。

        你应该测试new Element() vs document.createElement() vs .innerHTML的速度

        还可以尝试“在内存中”构建 dom 树,然后将其附加到文档的末尾。

        最后请注意,您不会经常查看 .length 或其他类似的内容。

        【讨论】:

        【解决方案4】:

        您可以创建一个字符串表示并将其添加为节点的innerHTML

        【讨论】:

          【解决方案5】:

          我在大约 3000 行复杂数据的表中遇到过类似的问题,因此您的代码存在一些不完全正确的问题。它是如何在 Firefox 中运行的?你能检查几个不同的浏览器吗?

          您是否在任何地方绑定到 onPropertyChange?这是一个非常危险的 ie 事件,它让我更早地引起了严重的 ie 特定头痛。你在任何地方都使用 CSS 选择器吗?这些在ie上是出了名的慢。

          【讨论】:

          • 你最后两个问题是否定的。 Firefox 没问题,但在更新期间明显没有响应。我将研究改进代码本身
          猜你喜欢
          • 1970-01-01
          • 2011-07-25
          • 2014-09-20
          • 2017-08-07
          • 1970-01-01
          • 2020-10-28
          • 1970-01-01
          • 2013-05-13
          • 1970-01-01
          相关资源
          最近更新 更多