Что лучше: создание строки html или создание элемента DOM класса jquery?

Хорошо, я переписываю некоторые функции JS Vanilla в моем текущем проекте, и я нахожусь в точке, где много 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);

?

Ответ 1

С точки зрения производительности: зависит от.

В вашем кратком примере быстрее добавить текст, поскольку на самом деле вы не создаете никаких элементов 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-контакт: 25 мс, Манипуляция DOM: 149 мс.

Однако, если вы можете кэшировать сложный фрагмент, вы получаете возможность неоднократно не создавать эти элементы DOM, просто клонируя их. Во втором тестировании DOM выигрывает, потому что, хотя метод HTML создает эту коллекцию элементов DOM 5000 раз, второй метод кэширования создает только один раз и клонирует его 5000 раз. В этом тесте: HTML Concat: 282ms, Манипуляция DOM: 157 мс.

Я понимаю, что это не прямо в ответ на ваш вопрос, но на основе комментариев кажется, что есть некоторое любопытство в отношении производительности, поэтому просто даем то, что вы можете видеть/тестировать/играть с.

Ответ 2

Я протестировал код 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');

Вывод заключается в том, что кэширование DOM работает быстрее, только если вы планируете повторять один и тот же фрагмент HTML снова и снова. Если не пойти с конкатенацией строк.

Я не нашел преимуществ скорости при использовании метода Array.join. Однако я не тестировал это полностью (возможно, это изменится, если число итераций больше).

Ответ 3

Благодарите DOM за использование методов innerHTML. Во-первых, манипуляция DOM будет корректно обрабатывать символы, которые должны быть экранированы с помощью innerHTML. Для другого, это обычно быстрее, иногда намного быстрее.

Ответ 4

В общем, если у меня есть много 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(''));