.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("我也遇到了大表重绘(大约 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[:])? [复制]