chrome“appendChild”真的那么慢吗?

Posted

技术标签:

【中文标题】chrome“appendChild”真的那么慢吗?【英文标题】:Is chromes "appendChild" really that slow? 【发布时间】:2012-02-13 08:47:25 【问题描述】:

我有一个完全使用document.createElementdocument.appendChild 生成应用程序DOM 的框架。现在应用程序变得越来越大,我注意到 Chrome 与其他浏览器一样需要更长的时间来构建 DOM。

所以,我创建了以下性能测试:

window.onload = function()
    var now = new Date().getTime();
    for(var i = 0; i < 10000; i++)
        document.body.appendChild(document.createElement("div"));
    
    setTimeout(function()
        console.log(new Date().getTime() - now);
    ,0);


这个测试的结果很有意思:

铬 16:700+ 火狐9:560 IE 9:210 Opera 11.60: 51

Chrome 的完成时间是 Opera 的 14 倍多。 这不仅仅是一个毫无意义的基准!我真的可以在我的应用中感受到这种不同。

Chrome 在 DOM 操作上这么慢是正常的吗? 有没有办法加快速度?

谢谢!

【问题讨论】:

setTimeout 似乎会耽误你的时间。 @Domenic 你需要 setTimeout 在这种基准测试中,以便浏览器在你得到时间之前确实可以工作 @Esailija 不正确,正如我的性能测试所示,它让你失望:jsperf.com/appendchild-from-so 回想一下,setTimeout 在不同的浏览器中被限制为不同的值。 @Domenic jsperf 有什么相关性?无论如何:jsfiddle.net/rZzYk/2 @Domenic 但它返回正确的结果,您至少可以使用时间线工具在 chrome 中验证。根据时间轴,渲染耗时 3.04 秒,但第一个记录的数字是 600 毫秒。那是因为浏览器仅在记录该时间后才呈现。如果您将日志记录推迟到线程空闲后立即进行(即setTimeout( , 0),您将获得渲染完成后的时间。 【参考方案1】:

更新 2

这是一种骇人听闻的解决方案,可能值得进行一点浏览器检测。它使我的测试性能降低到不到原来的 1/10

你可以在追加之前display='none'容器,之后再显示。你可能会得到一点闪光,但这可能比长时间的延迟要好。

window.onload = function()

    var content = String.fromCharCode(Math.floor(Math.random() * 1000));

       // cache it in case it is already set
    var disp = document.body.style.display;

    document.body.style.display = 'none';

    var now = new Date().getTime();

    for(var i = 0; i < 10000; i++)
        document.body.appendChild(document.createElement("div"))
          .appendChild(document.createTextNode( content ));
    

    setTimeout(function()
        console.log(new Date().getTime() - now);
        document.body.style.display = disp || ''; // restore it
    ,0);
;

这是我对documentFragment 的预期性能提升。


更新

在运行 modified version 的 @Esailija's jsFiddle 测试以包含 documentFragment 之后,它似乎在 Chrome(或 Opera 中)没有任何区别,因此它显示为虽然 Chrome 更慢。


“有没有办法加快速度?”

我猜如果您使用 documentFragment,然后使用单个 .appendChild 附加到 DOM,您将获得更好的性能。

window.onload = function()
    var now = new Date().getTime();

      // create a documentFragment
    var frag = document.createDocumentFragment();

    for(var i = 0; i < 10000; i++)
        frag.appendChild(Div());  // append to the documentFragment
    

      // append the documentFragment (which is emptied)
    document.body.appendChild(frag);

    setTimeout(function()
        console.log(new Date().getTime() - now);
    ,0);

    function Div()
        var This = document.createElement("div");
        return This;
    

【讨论】:

使用 documentFragment 会极大地加速它,或者任何不属于 DOM 的容器。我猜 Opera 在“幕后”做这件事,这并不总是预期的行为。 您的更新是正确的,使用您的代码并不能真正加快速度。有区别,但只有50ms左右...我仍然认为应该有解决方案...:S @VanCoding:考虑到大部分时间来自页面重绘,我不知道你是否真的能够改变它。如果您希望避免浏览器出现冻结,您可以将任务分解为更小的异步块,以允许用户仍然与页面交互。除此之外,我不知道你能做些什么来提高 Chrome 的重绘性能。这在引擎盖下很好。 是的。我会将此作为错误报告给 chrome 开发团队。 @VanCoding:我为你准备了一个骇人听闻的解决方案。如果你在循环之前执行document.body.style.display = 'none';,那么在setTimeout 执行...display = '',性能似乎完全消除了重绘性能。我会更新的。【参考方案2】:

我觉得这很正常……

html 对象操作(宽度、高度和不透明度)也是如此,尤其是在您使用 CSS3 时。

我编写了一个幻灯片(不使用 jQuery,我讨厌它),它在 FF、IE、Opera、Safari 中运行顺利……但在 Chomre 中却没有。在 Chrome 中,速度慢得令人难以置信(仅在较新的 Chrome 版本中,在 v12 等旧版本中速度更快)。

【讨论】:

【参考方案3】:

您的测试似乎有缺陷。如果你做一个纯粹的appendChild 测试,Chrome 会遥遥领先:

http://jsperf.com/appendchild-from-so

【讨论】:

只对 appendChild 的调用进行基准测试是不够的!调用本身确实很快,但是在JS进入idle之后,chrome还有很多事情要做,才能开始下一个tick。在所有其他浏览器中,这似乎有所不同。但是:我想对整个过程进行基准测试,包括所有处理时间。

以上是关于chrome“appendChild”真的那么慢吗?的主要内容,如果未能解决你的问题,请参考以下文章

ifelse 真的每次都计算它的两个向量吗?慢吗?

与 Pynsq 相比,Nsqjs 真的慢吗?

Rails 3 Cli 执行命令真的很慢吗?

C ++中的异常真的很慢吗

C++ 程序真的比类似的 C 程序慢吗? [关闭]

在 Android 上部署 Qt 应用程序真的很慢吗?