49

该站点在 3 种不同方法之间进行了测试,似乎.html是最快的,其次是.append. 其次是.innerHTML。有人可以向我解释原因吗?

这是对三种方法进行比较的网站。

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

我不明白以下部分:

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

有人可以简化这个吗?

4

7 回答 7

56

这三个对我来说都很慢。在每次迭代中修改 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

在此处输入图像描述

于 2013-08-23T03:19:30.923 回答
52

那个基准毫无价值。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

于 2013-08-23T03:12:07.443 回答
15

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

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 );
}
于 2013-08-23T03:20:30.787 回答
6

正如 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 //后备速度慢,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

于 2019-01-21T17:35:02.157 回答
4

我认为使用 @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

于 2013-08-23T04:02:11.573 回答
2

我也遇到了大表重绘(大约 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 毫秒 :))

于 2015-02-17T07:26:52.937 回答
1

6年后

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

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

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

于 2019-12-16T13:08:23.040 回答