代码之家  ›  专栏  ›  技术社区  ›  matt b

是否可以在不阻塞浏览器的情况下添加大量的DOM节点?

  •  1
  • matt b  · 技术社区  · 16 年前

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

    最近,我在Internet Explorer中解决了由于这个DOM破坏和创建代码而导致的大量内存泄漏问题(其中大多数都与JavaScript对象和DOM对象之间的循环引用有关,而我们使用的JavaScript库会悄悄地保留对用它创建的每个JS对象的引用。 new Element(...) 直到卸载页面)。

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

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

    似乎运行行和单元创建代码乘以100+个数据块是导致CPU使用率激增的原因,函数运行“太长”(从IE的角度看),从而导致IE为用户生成此警告。我还注意到,当“update screen”函数为100行运行时,即在函数完成之前不会重新呈现表内容(因为JS解释器在这段时间内使用了100%的CPU,我假设)。

    所以我的问题是:在javascript中,有没有什么方法可以让浏览器暂停JS的执行并重新呈现DOM?如果没有,是否有处理创建大量DOM节点和 让浏览器窒息?

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


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

    我的测试还显示了一种更快的方法,至少对于像我这样的简单测试来说是这样的:使用 DocumentFragments as described by John Resig . 用IE7在同一台机器上运行相同的测试需要247毫秒, 9X 改进了我原来的方法!

    5 回复  |  直到 16 年前
        1
  •  6
  •   Greg    16 年前

    一百 <tr> S不算太多…你还在使用那个框架吗? new Element() ?这可能就是原因。

    你应该测试一下 新元素() VS document.createElement() VS .innerHTML

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

    最后,注意不要看。长度太频繁,或者其他的点点滴滴。

        2
  •  1
  •   krosenvold    16 年前

    在复杂数据的第3000行表中,我遇到过类似的问题,因此您的代码有一些不完全正确的地方。它是如何在火狐中运行的?你能签入几个不同的浏览器吗?

    是否绑定到OnPropertyChange?这是一个非常危险的IE事件,早先引起我严重的IE特有的头痛。您是否在任何地方使用CSS选择器?这是出了名的慢。

        3
  •  1
  •   community wiki Mehrdad Afshari    16 年前

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

        4
  •  0
  •   Luca Matteis    16 年前

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

        5
  •  0
  •   epascarello    16 年前

    避免使用一个较大的for循环在一个较大的步骤中呈现所有数据。看看把数据分成更小的块。

    用while循环呈现每个较小的块。完成该块后,用setTimeout[时间1毫秒]调用下一个块,给浏览器一个“喘息”。

    您可以避免同时使用while循环,只需使用settimeout。

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

    另一件事是不要将每个元素单独附加到文档中。研究如何创建新tbody,将新行追加到新tbody,并将tbody追加到表中。

    还有很多其他的事情会导致应用程序缓慢。把它们全部冲掉可能很有趣。

    这里有一个关于警告的清晰研究: http://ajaxian.com/archives/what-causes-the-long-running-script-warning