哪个更好:使用字符串生成HTML还是使用jQuery创建DOM元素?

16

好的,我正在重新编写当前项目中的一些普通JS函数,并且现在有很多HTML代码需要生成,如工具提示等。

我的问题是,哪种做法更好/更优选:

var html = '<div><span>Some More Stuff</span></div>';
if (someCondition) {
    html += '<div>Some Conditional Content</div>';
}
$('#parent').append(html);

或者

var html = $('<div/>').append($('<span/>').append('Some More Stuff'));
if (someCondition) {
    html.append($('<div/>').append('Some conditionalContent');
}
$('#parent').append(html);

?

4个回答

37

从性能的角度来看:这取决于具体情况

在你提供的简短示例中,追加文本会更快,因为直到最后你实际上并没有创建任何DOM元素。然而,如果你需要大量这样的操作,那么字符串拼接所耗费的时间就会逐渐增加,而缓存文档片段的性能优势也就凸显出来了。

当你执行$(html)时,jQuery会将其作为文档片段进行缓存(前提是字符串大小小于512字节),但是如果你只是缓存$("<div />"),则性能提升并不明显。然而,如果你需要执行这种操作数千次,那么字符串拼接的代价随着字符串长度的增加而变得越来越昂贵,而缓存文档片段的成本则相对稳定。

更新:下面是一些示例,你可以使用Firebug来查看控制台时间:

你可以在这里运行代码:http://jsfiddle.net/Ps5ja/

console.time('concat');
var html = "";
for(var i = 0; i < 500; i++) {
    html += '<div><span>Some More Stuff</span></div>';
    html += '<div>Some Conditional Content</div>';
}
var elem = $(html);
console.timeEnd('concat'); //25ms

console.time('DOM');
var parent = $("<div />")
for(var j = 0; j < 500; j++) {
    parent.append($('<div/>').append($('<span/>', {text :'Some More Stuff'})));
    parent.append($('<div/>',{ text: 'Some conditionalContent' }));
}
console.timeEnd('DOM'); //149ms

console.time('concat caching');
var html = "";
for(var i = 0; i < 5000; i++)
    html += '<div><span>Some More Stuff</span></div><div>Some Conditional Content</div>';
var elem = $(html);
console.timeEnd('concat caching'); //282ms

console.time('DOM caching');
var parent = $("<div />")
for(var j = 0; j < 5000; j++)
    parent.append('<div><span>Some More Stuff</span></div><div>Some Conditional Content</div>');
console.timeEnd('DOM caching'); //157ms
注意:字符串测试中的var elem = $(html);是为了确保我们创建相同的DOM元素,否则您将比较字符串连接和实际的DOM创建,这几乎不公平,并且也没有什么用 :)

从上面可以看出,当缓存的片段更复杂时,缓存的影响越大。在第一个测试中,也就是您的示例未经过清理的情况下,由于有许多小操作进行,所以DOM会输掉,在此测试中(在我的机器上,但您的比率应该大致相同):HTML Contact: 25msDOM Manipulation: 149ms

然而,如果您可以缓存复杂的片段,则可获得不重复创建这些DOM元素的好处,只需克隆它们。在第二个测试中,由于HTML方法创建了那个DOM元素集合5000次,因此第二个缓存方法仅创建了一次,并将其克隆5000次。在此测试中:HTML Concat: 282msDOM Manipulation: 157ms

我意识到这并不是针对您的问题直接的回答,但基于评论似乎对性能有一些好奇,因此提供一些您可以看到/测试/玩耍的内容。


2
很想知道为什么会有人对此进行负评。这个人错了吗?还是不错的?请启迪我们。 - Dave Markle
同意:为什么要踩,这个推理听起来很合理啊。我不会做成千上万次的字符串拼接,所以我认为这样做没问题。顺便说一句,据我所知,现在Firefox和Chrome都使用StringBuilder风格的数组方法进行字符串拼接,因此字符串拼接可以非常快速。 - Ed James
我只能猜测那个 Downvoter 可能认为这是过早的优化? - hippietrail

5

我测试了Nick Craver提交的代码,并发现DOM缓存只有在元素内容不变的情况下才能更快地工作。但是,如果你在每次for循环迭代中修改字符串,速度会显著降低。

这是同样的代码修改版(在Fiddle上测试:http://jsfiddle.net/Ps5ja/42/

console.time('concat');
var html = "";
for(var i = 0; i < 500; i++) {
    html += '<div><span>Some More Stuff</span></div>';
    html += '<div>Some Conditional Content</div>';
}
var elem = $(html);
console.timeEnd('concat');

console.time('DOM');
var parent = $("<div />")
for(var j = 0; j < 500; j++) {
    parent.append($('<div/>').append($('<span/>', {text :'Some More Stuff'})));
    parent.append($('<div/>',{ text: 'Some conditionalContent' }));
}
console.timeEnd('DOM');

console.time('concat caching');
var html = "";
for(var i = 0; i < 10000; i++)
    html += '<div><span>Some More Stuff</span></div><div>Some Conditional Content'+i+'</div>';
var elem = $(html);
console.timeEnd('concat caching');

console.time('concat array.join');
var arr = [];
for(i = 0; i < 10000; i++)
    arr.push('<div><span>Some More Stuff</span></div><div>Some Conditional Content'+i+'</div>');

var elem = $(arr.join(''));
console.timeEnd('concat array.join');

console.time('DOM caching - NO modification');
var parent = $("<div />")
// here the contained text is unchanged in each iteration
for(var j = 0; j <10000; j++)
    parent.append('<div><span>Some More Stuff</span></div><div>Some Conditional Content</div>');
console.timeEnd('DOM caching - NO modification');

console.time('DOM caching with modification');
var parent = $("<div />")
// here the contained text is modified in each iteration
// (the value od J is appended to the text)
for(var j = 0; j <10000; j++)
    parent.append('<div><span>Some More Stuff</span></div><div>Some Conditional Content'+j+'</div>');
console.timeEnd('DOM caching with modification');

结论是,只有当您计划一遍又一遍地复制相同的HTML片段时,DOM缓存才能更快。如果不是这样,请使用字符串连接。

我没有发现使用Array.join方法有任何速度优势。但是我没有进行彻底的测试(如果迭代次数更多,则可能会更改)。


2

建议优先使用DOM操作而不是innerHTML方法。一方面,DOM操作可以正确处理需要使用innerHTML转义的字符。另一方面,它通常更快,有时甚至非常快。


我在这两个例子中都没有使用innerHTML:这是关于从头开始生成而不是直接操作现有元素的讨论。这基本上就是字符串连接与元素创建的区别。 - Ed James
1
@EdWoodcock $("<div>1 2 3</div>") 使用 innerHTML 实现,所以你确实在使用 innerHTML - cletus
不知道这个,有用的信息,但是在第二个例子中,我将div初始化为空白的(据我所知不会使用innerHTML?),而在第一个例子中,我从头开始构建一个字符串,然后使用append(我假设它只执行一次innerHTML)。 - Ed James
2
PPK的测试表明innerHTML比DOM操作更快(IE更快得多):http://www.quirksmode.org/dom/innerhtml.html - Jeffery To

0
通常情况下,如果我有很多HTML需要生成,我会将它们全部收集到一个字符串中,然后让浏览器一次性生成所有元素。
如果涉及大量条件语句或循环,则可能希望使用Array.join()而不是使用+进行字符串连接。使用字符串连接,浏览器将生成大量中间字符串,这可能非常慢;Array.join()跳过所有这些中间字符串。对于这些情况,我会做如下处理:
var html = ['<div><span>Some More Stuff</span></div>'];
for (var i = 0; i < 1000; i++) {
    html.push('<div>Some Loop Content</div>');
}
$('#parent').append(html.join(''));

正如我之前所说的,FF以及据我所知的Chrome和Opera会自动为字符串连接执行此方法,在FF中,+=实际上比数组方法更快。 - Ed James
我猜测IE不会支持你的项目? - Jeffery To

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接