关于javascript:.append VS .html VS .innerHTML性能

.append VS .html VS .innerHTML performance

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

这是在三种方法之间进行比较的站点。

我已经阅读了这个与此相关的问题,但我不太理解给出的答案,并且该问题并未真正详细说明.innerHTML

我不理解以下部分:

A temporary element is created, let's call it x. x's innerHTML is set to the string of HTML that you've passed. Then jQuery will transfer each of the produced nodes (that is, x's childNodes) over to a newly created document fragment, which it will then cache for next time. It will then return the fragment's childNodes as a fresh DOM collection.
Note that it's actually a lot more complicated than that, as jQuery does a bunch of cross-browser checks and various other optimisations. E.g. if you pass just to jQuery(), jQuery will take a shortcut and simply do document.createElement('div').

有人可以简化吗?


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

jQuery看起来更快,因为jQuery首先准备了所有HTML字符串,而其他的每次迭代都执行一个操作。还要注意,jQuery.html()尽可能使用innerHTML

基准测试中的jQuery

1
2
3
4
5
6
var html = '';
for (var i = 0; i < len; i++) {
  html += 'Test ' + i + '';
}

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

来自基准的innerHTML

1
2
3
4
var list = document.getElementById('list');
for (var i = 0; i < len; i++) {
  list.innerHTML = list.innerHTML + 'Test ' + i + '';
}

如果将innerHTML的测试编写为:

1
2
3
4
5
6
7
8
var list = document.getElementById('list');
var html = '';

for (var i = 0; i < len; i++) {
    html += 'Test ' + i + '';
}

list.innerHTML = html;

http://jsben.ch/#/yDvKH


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

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

我刚刚在其中添加了一个新测试:

1
2
3
4
5
6
var html = [];
for (var i = 0; i < len; i++) {
  html.push('Test ' + i + '');
}

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

这又快得多了。 :)

我在Firefox中执行的方法的运行速度为26k Ops / sec,而速度为1,000、10,000和13

enter image description here


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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 );
}


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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Chrome:
createFragment 312.80 ms  
hyperHTML      253.10 ms    
innerHTML       62.70 ms  
$.append       183.40 ms

Chrome (extensions off):
createFragment 225.10 ms
hyperHTML      139.80 ms
innerHTML       47.80 ms
$.append       170.90 ms

Firefox:
createFragment 141 ms
hyperHTML       84 ms
innerHTML       25 ms
$.append        90 ms

Edge:
createFragment 422.50 ms
hyperHTML      184.60 ms
innerHTML       44.00 ms
$.append      1629.69 ms

IE11:
createFragment   1180.29 ms
hyperHTML       13315.59 ms //slow fallbacks, IE sucks
innerHTML         125.70 ms
$.append         2382.49 ms

我认为这很简单。 JavaScript在解析和创建元素方面不如浏览器快,因为浏览器是机器特定的编译代码。您要做的不只是交出HTML并让浏览器无间断地工作。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
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';
}


我认为建议使用@Brat可以使innerHTML更快。

在创建循环和附加字符串时,最好先使用变量。
它使您的表现更加出色。

好代码:

1
2
3
4
5
var html = '';
for (var i = 0; i < len; i++) {
  html += 'Test ' + i + '';
};
$('#list').append(html);

效率不高的代码:

1
2
3
4
for (var i = 0; i < len; i++) {
  var html = 'Test ' + i + '';
  $('#list').append(html);
}

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


大表重绘(大约10x100大小)也有问题。重绘整个表格大约需要300毫秒。

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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毫秒:))


6年后

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

在Chrome和Firefox上,我的观察是,运行时间都是相同的,付出或付出的代价只有几个百分点。

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