.append VS .html VS .innerHTML 性能

Posted

技术标签:

【中文标题】.append VS .html VS .innerHTML 性能【英文标题】:.append VS .html VS .innerHTML performance 【发布时间】:2013-08-25 23:35:11 【问题描述】:

本网站在 3 种不同的方法之间进行了测试,似乎.html 最快,其次是.append。其次是.innerHTML。谁能给我解释一下原因?

这是三种方法中的site which does the comparison。

我已经阅读了这个相关的this SO question,但我并不真正理解给定的答案,而且这个问题并没有真正详细说明.innerHtml

下面的部分我没看懂:

创建了一个临时元素,我们称它为 x。 x 的 innerHTML 设置为您传递的 HTML 字符串。然后 jQuery 会将每个生成的节点(即 x 的子节点)转移到新创建的文档片段中,然后将其缓存以备下次使用。然后它将片段的 childNodes 作为新的 DOM 集合返回。 请注意,它实际上比这要复杂得多,因为 jQuery 做了一堆跨浏览器检查和各种其他优化。例如。如果你只将<div></div> 传递给 jQuery(),jQuery 会走捷径,简单地执行 document.createElement('div')。

有人可以简化一下吗?

【问题讨论】:

返回一个修订版:jsperf.com/jquery-append-vs-html-list-performance/19 修订版 20 只是被一些傻瓜破坏了。 您的测试基于执行方法存在缺陷。很多时候,性能只取决于算法和实现的选择(例如,var i=1; 的结果与var i;for(var c=0,n=10000;c<n;c++)i=1; 相当,但第一个显然更优化,是更好的选择) 这里是 4 种不同情况的工作基准:jsben.ch/#/yDvKH 【参考方案1】:

这三个对我来说都很慢。 每次迭代修改 dom 很慢。

http://jsperf.com/jquery-append-vs-html-list-performance/24

我刚刚在那里添加了一个新测试:

var html = [];
for (var i = 0; i < len; i++) 
  html.push('<div>Test ' + i + '</div>');


document.getElementById('list').innerHTML = html.join('');

这又快了很多。 :)

我在 Firefox 中的方法是 26k Ops/sec vs 1,000、10,000 和 13

【讨论】:

是的,看到了结果。从来不知道数组有这么快。 @Bart - 我们在使用模板框架构建 50 列 x 200 行表客户端时遇到了巨大问题。我从destroyallsoftware.com/talks/wat 得到了连接整个表格的想法。我们使用它从 5-10 秒渲染到即时渲染。 (IE 7 仍然需要大约 2 秒) 这令人印象深刻。顺便说一句,那次谈话非常搞笑:-D 谢谢!这种优势复合了更长和更复杂的数组(例如,具有长字符串的数组)。我做了这个转换,发现我的性能提高了 600 倍以上 - 1,800 毫秒 vs 3 毫秒。【参考方案2】:

那个基准毫无价值。 innerHTML 总是比 DOM 操作快。

jQuery 似乎更快,因为它首先准备一个包含所有 HTML 的字符串,而其他人在每次迭代时执行一个操作。另请注意,jQuery.html() 尽可能使用innerHTML

来自基准的jQuery

var html = '';
for (var i = 0; i < len; i++) 
  html += '<div>Test ' + i + '</div>';


$('#list').html(html);

来自基准测试的innerHTML

var list = document.getElementById('list');
for (var i = 0; i < len; i++) 
  list.innerHTML = list.innerHTML + '<div>Test ' + i + '</div>';


innerHTML 的测试如果写成这样会快很多:

var list = document.getElementById('list');
var html = '';

for (var i = 0; i < len; i++) 
    html += '<div>Test ' + i + '</div>';


list.innerHTML = html;

http://jsben.ch/#/yDvKH

【讨论】:

请加style='display:none'。这样看起来更好:jsperf.com/jquery-html-vs-innerhtml-the-better-way/2 所以javascript函数比jQuery更高效? @invisal 已修复:P @MuhamadAkbarBinWidayat 是的。本机代码总是更快。 jQuery 自己使用它。除了 innerHTML 和 DOM 操作之外,真的没有多少可以操作文档了。 要进行适当的比较,您应该保持所有内容相同,除了您要比较的确切内容,这与我见过的许多 jsperf 比较不同。这是一个简单、更准确的性能比较:jsperf.com/innerhtml-vs-html-vs-empty-append【参考方案3】:

.html 使用带有大量额外代码的.innerHTML 时,.html 如何比.innerHTML 更快?这里.html 在 jQuery 中实现(直接取自 jQuery 文件)。

html: function( value ) 
    return jQuery.access( this, function( value ) 
        var elem = this[0] || ,
            i = 0,
            l = this.length;

        if ( value === undefined ) 
            return elem.nodeType === 1 ?
                elem.innerHTML.replace( rinlinejQuery, "" ) :
                undefined;
        

        // See if we can take a shortcut and just use innerHTML
        if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
            ( jQuery.support.htmlSerialize || !rnoshimcache.test( value )  ) &&
            ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&
            !wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) 

            value = value.replace( rxhtmlTag, "<$1></$2>" );

            try 
                for (; i < l; i++ ) 
                    // Remove element nodes and prevent memory leaks
                    elem = this[i] || ;
                    if ( elem.nodeType === 1 ) 
                        jQuery.cleanData( getAll( elem, false ) );
                        elem.innerHTML = value;
                    
                

                elem = 0;

            // If using innerHTML throws an exception, use the fallback method
             catch(e) 
        

        if ( elem ) 
            this.empty().append( value );
        
    , null, value, arguments.length );

【讨论】:

有趣的是,这个答案实际上是如何提出一个带有解释的问题的! :)【参考方案4】:

正如 Bart 所说,innerHTML 总是比 DOM 操作快

我正在测试 hyperHTML,所以我想我会分享我的结果。实际上我最初并没有在 CodePen 中运行我的基准测试,有趣的区别在于 jQuery 时间更接近在 CodePen 中运行的 innerHTML。

铬: 创建片段 312.80 毫秒 超HTML 253.10 毫秒 内部HTML 62.70 毫秒 $.append 183.40 毫秒 Chrome(扩展关闭): 创建片段 225.10 毫秒 超HTML 139.80 毫秒 内部HTML 47.80 毫秒 $.append 170.90 毫秒 火狐: 创建片段 141 毫秒 超HTML 84 毫秒 内部HTML 25 毫秒 $.append 90 毫秒 边缘: 创建片段 422.50 毫秒 超HTML 184.60 毫秒 内部HTML 44.00 毫秒 $.append 1629.69 毫秒 IE11: 创建片段 1180.29 毫秒 hyperHTML 13315.59 ms //slow fallbacks,IE 很烂 内部HTML 125.70 毫秒 $.append 2382.49 毫秒

我认为这一切都很简单。 JavaScript 在解析和创建元素方面不如浏览器快,因为浏览器是特定于机器的编译代码。最好的办法就是交出 HTML 并让浏览器不间断地完成工作。

某些性能差异可能是由于 XSS 检查造成的,这似乎是谨慎的。

function runbench()
  var data = [];
  for (var i = 0; i < 10001; i++) 
      data.push("<span>" + i + "</span>");
  

  var perf=[];
  var t0 = performance.now();
  var c = document.createDocumentFragment();
  for (var i = 0; i < 10001; i++) 
      var e = document.createElement("span");
      e.innerHTML = data[i];
      c.appendChild(e);
  
  document.querySelector('#createFragment').appendChild(c);
  document.querySelector('#createFragment').classList='done';
  var t1 = performance.now();
  perf.push(t1-t0);

  var t0 = performance.now();
  document.querySelector('#innerHTML').innerHTML = data.join('');
  document.querySelector('#innerHTML').classList='done';
  var t1 = performance.now();
  perf.push(t1-t0);

  var t0 = performance.now();
  $('#jqhtml').html(data.join(''));
  document.querySelector('#jqhtml').classList='done';
  var t1 = performance.now();
  perf.push(t1-t0);

  var t0 = performance.now();
  $('#jqappend').append(data.join(''));
  document.querySelector('#jqappend').classList='done';
  var t1 = performance.now();
  perf.push(t1-t0);

  var t0 = performance.now();
  hyperHTML.bind(document.querySelector('#hyperHTML'))       
  `$data.map(function (item) 
      return "<span>" + item + "</span>";
  )`;
  document.querySelector('#hyperHTML').classList='done';
  var t1 = performance.now();
  perf.push(t1-t0);

  var stats = [];
  stats.push("<table>")
  stats.push("<tr><td>createFrag: </td><td>" + perf[0].toFixed(2) + "</td></tr>");
  stats.push("<tr><td>innerHTML: </td><td>" + perf[1].toFixed(2) + "</td></tr>");
  stats.push("<tr><td>$.html: </td><td>" + perf[2] .toFixed(2) + "</td></tr>");
  stats.push("<tr><td>$.append: </td><td>" + perf[3] .toFixed(2) + "</td></tr>");
  stats.push("<tr><td>hyperHTML: </td><td>" + perf[4].toFixed(2) + "</td></tr>");
  stats.push("</table>");
  $('#performance').html(stats.join(''));
  document.querySelector('#performance').classList='done';

https://codepen.io/jwhooper/pen/GzKwMV

【讨论】:

【参考方案5】:

我认为使用@Brat 的建议,innerHTML 会更快。

并且在创建循环和附加字符串时应该首先使用变量。 就是让你的表现更出色。

好代码:

var html = '';
for (var i = 0; i < len; i++) 
  html += '<div>Test ' + i + '</div>';
;
$('#list').append(html);

效率不高的代码:

for (var i = 0; i < len; i++) 
  var html = '<div>Test ' + i + '</div>';
  $('#list').append(html);

例如:http://jsben.ch/#/yDvKH

【讨论】:

我最后测试的一个更快的测试是在循环外有一个数组 var html = [] 并在循环内使用 html.push("...") 并且一旦循环结束,使用 element.innerHTML = html.join("") 尝试用这个运行测试,它的数量级更快【参考方案6】:

我也遇到了大表重绘(大约 10x100 大小)的问题。重绘整个表格大约需要 300 毫秒。

原因不在于 jQuery.append() 也不在于 dom.innerHTML,而在于每次都附加每个元素。

最快的方法是连接所有元素的 html 代码,然后将其附加到 DOM。 像这样:

function redrawMyTable( myData )

    var innerHTML = '';
    for ( var i = 0; i < myData.length; i++ )
    
      innerHTML += createRowFromData( myData[i] );
    

    myTableTbody.innerHTML = innerHTML;

function createRowFromData( rowData )

    var rowHTML = '';
    for ( var i = 0; i < rowData.length; i++ )
    
      rowHTML += createCellFromData( rowData[i] );
    
    return rowHTML;

function createCellFromData( cellData )

    //Do everything you need, and return HTMl code as a string
    return cellHTML;

现在只需要 20-30 毫秒(相对于 300 毫秒 :))

【讨论】:

【参考方案7】:

6 年后

要点是 - 不要操纵实时 DOM。在外面做。今天,在哪里都无所谓。您可以使用 HTML 字符串、DocumentFragment(不包括 Internet Explorer)或创建新元素但不要将其添加到 DOM,根据需要填充它,然后添加它。

在 Chrome 和 Firefox 上,我的观察是它们的运行时间都是一样的,给或取几个百分点。

在存储在数组中的块中构建一个长的 HTML 字符串,然后加入('')-ed 也不再需要了。几年前,我测量了很大的时差。今天不行。第一点:没有可识别的时间差(在 Chrome 和 FF 上),第二点:时间并没有在这一点丢失,而是在渲染中。

【讨论】:

以上是关于.append VS .html VS .innerHTML 性能的主要内容,如果未能解决你的问题,请参考以下文章

Pandas DataFrame concat vs append

Python-Notes-1: append VS extend

python中的list.append(another_list) vs list.append(another_list[:])? [复制]

数据库对比 | MySQL vs PostgreSQL

Jquery - 追加vs AppendTo

jQuery .html() 与 .append()