Правильный способ динамически генерировать HTML с помощью JQuery - PullRequest
18 голосов
/ 07 октября 2011

Я нашел несколько разных и противоречивых ответов на эту тему.

Я создаю приложение, которое работает в основном с html, динамически генерируемым jQuery, на основе результатов, полученных из базового API в форме данных JSON.

Некоторые мои коллеги (лично) сказали мне, что лучшим способом было бы сделать что-то вроде этого:

var ul = $("<ul>").addClass("some-ul");
$.each(results, function(index) {
  ul.append($("<li>").html(this).attr("id", index));
});
$("body").append($("<div>").attr("id", "div-id").addClass("some-div").append(ul));

и т. Д.Мне сказали, что это «обновляет DOM напрямую, а не разбирает html для его достижения».

Однако я вижу много кода, подобного этому (тот же пример):

var toAppend = '<div class="some-div" id="div-id"><ul>';
$.each(results, function(index) {
  toAppend += '<li id="' + index + '">' + this + '</li>';
});
toAppend += '</ul></div>'

Что лично я считаю не таким элегантным - но лучше ли?Я нашел вопрос в течение нескольких минут и нашел эту статью .По сути, речь идет о радикальном увеличении производительности с помощью конкатенации строк - мой «второй путь».

Основная проблема этой статьи заключается в том, что она была выпущена в 2009 году, и обсуждаемая версия jQuery - 1.3.Сегодня текущим выпуском является версия 1.6.4, которая может вести себя совершенно иначе.И это вопрос большинства статей на эту тему, которые я уже нашел, и я также почему-то с подозрением отношусь к их достоверности.

Вот почему я решил опубликовать здесь вопрос и спросить - какой метод генерации DOMна самом деле правильный, основанный на производительности?

ВАЖНОЕ РЕДАКТИРОВАНИЕ:

Я написал небольшой тест для проверки, какой подход лучше с точки зрения производительности.

jsFiddle - версия объединения

jsFiddle - версия объединения массива

Код:

var text = "lorem ipsum";
var strings = $("#strings");
var objects = $("#objects");
var results = $("#results");

// string concatenation
var start = new Date().getTime();
var toAppend = ['<div class="div-class" id="div-id1"><ul class="ul-class" id="ul-id1">'];
for (var i = 1; i <= 20000; i++) {
    toAppend[i] = '<li class="li-class" id="li-id1-' + i + '">' + text + '</li>';
}
toAppend[i++] = '</ul></div>';
results.append(toAppend.join(""));
strings.html(new Date().getTime() - start);

// jquery objects
var start = new Date().getTime();
var ul = $("<ul>").attr("id", "ul-id2").addClass("ul-class");
for (var i = 0; i < 20000; i++) {
    ul.append($("<li>").attr("id", "li-id2-" + i).addClass("li-class"));
}
results.append($("<div>").attr("id", "div-id2").addClass("div-class").append(ul));
objects.html(new Date().getTime() - start);

Кажется, что работа со строками быстрее (вFirefox 7 примерно в 7 раз), чем с использованием объектов и методов jQuery.Но я могу ошибаться, особенно если в коде этого «эталонного теста» есть ошибки или ошибки, снижающие производительность.Не стесняйтесь вносить любые изменения.

Примечание: я использовал массив join из-за статьи, упомянутой ранее, вместо фактической конкатенации.

РЕДАКТИРОВАТЬ: Основываясь на предложении @hradac, я использовал фактическийконкатенация строк в тесте, и это действительно улучшило время.

Ответы [ 5 ]

11 голосов
/ 17 октября 2011

Прежде всего, этот вид микропроцессинга почти никогда не говорит вам, что вы действительно хотите знать.Во-вторых, ваши тесты разнообразны и не эквивалентны.Например, ваш первый пример генерирует строки, которые выглядят так:

<li class="li-class" id="li-id1-493">lorem ipsum</li>

, а ваши вторые строки выглядят так:

<li id="li-id2-0" class="li-class"></li>

Обратите внимание на другой порядок элементов и отсутствие "lorem ipsum""текст.Также не предпринимаются попытки очистить разделение результатов между тестами, чтобы избежать проблем с производительностью в результате появления первых 20 000 результатов.

Но помимо этих проблем возникает вопрос: «Действительно ли это мешает производительности?пользовательский опыт на стороне клиента? "Шутки в сторону?Вы отображаете такое количество текста таким образом, что вы видите заметные различия между альтернативными методами визуализации текста?

Я вернусь к тому, что сказали другие, используя шаблонизатор.Самые быстрые действительно довольно быстрые и даже имеют опции предварительной компиляции, чтобы вы могли повторно визуализировать тот же шаблон и получить быстрые результаты.Так что не верь мне.Вместо этого верьте демонстрации.Вот мой jsFiddle, чтобы продемонстрировать производительность новой библиотеки JsRender, которая должна заменить движок шаблонов jQuery ...

http://jsfiddle.net/LZLWM/10/

Примечание: загрузка JsRender может занять несколько секундв скрипку.Это потому, что я вытаскиваю это прямо из GitHub, и это не то, что GitHub особенно хорош в этом.Я не рекомендую это на практике.Тем не менее, это не меняет время, и это необходимо до тех пор, пока jsFiddle не начнет включать движки шаблонов в качестве опций.

Обратите внимание, что второй пример, намного ближе к реальному, генерирует 20 000 строк, используя JSON в качестве отправной точки ввремя примерно такое же, как у вашего самого быстрого теста (разница <50 мс на моей машине).Также обратите внимание на то, что и код, и шаблон намного понятнее и с ними легче работать, чем с любым беспорядком добавлений, и когда-либо когда-либо будет конкатенация строк.Сколько итераций мне понадобится, чтобы настроить мой шаблон по сравнению с тем, что вы делаете? </p>

Используйте что-то простое и прекратите тратить время на этот уровень микрооптимизации, когда это, вероятно, даже не нужно.Вместо этого используйте такие шаблоны (или любой из нескольких других хороших шаблонизаторов) и убедитесь, что у вас включены заголовки expires, вы используете CDN, на вашем сервере включено сжатие gzip и т. Д. Всематериал, который YSlow советует вам делать, потому что это полностью затмит последствия того, на что вы здесь смотрите.

6 голосов
/ 07 октября 2011

Проверьте шаблоны jquery -

http://api.jquery.com/category/plugins/templates/

4 голосов
/ 07 октября 2011

Вообще, я думаю, что удобочитаемость выше производительности, если у вас действительно нет проблем.Я бы выбрал второй подход, так как его легко узнать как стандартный HTML-фрагмент, и я думаю, что он менее подвержен ошибкам.

При первом методе мне приходится анализировать большой объем кода в моем minhd, чтобы простопредставьте, как будет выглядеть финальная строка (и, следовательно, где она может нуждаться в изменениях).

2 голосов
/ 13 октября 2011

По сути, первый метод использует несколько вызовов методов для .innerHTML для создания результата, тогда как второй метод использует только один. Это основная область, которая вызывает разницу во времени выполнения.

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

var toAppend = ['<div class="some-div" id="div-id"><ul>'];
$.each(results, function(index) {
  toAppend.push('<li id="' + index + '">' + this + '</li>');
});
toAppend.push('</ul></div>');
$(target).append(toAppend.join(""));

Обычно я использую метод массива только для обеспечения согласованности.

Редактировать: hradac прав, метод объединения теперь быстрее.

1 голос
/ 07 октября 2011

Ваш первый подход лучше. Идея состоит в том, чтобы не трогать DOM, пока вы не должны В обоих примерах вы создаете UL в памяти, а затем в конце присоединяете его к DOM с помощью body.append().

Тем не менее, предпочтительный способ построить дерево в вашем первом примере. Конкатенация строк немного медленнее (конечно, мы говорим о миллисекундах). Однако, если вам придется делать это много раз на странице, это может стать значительным.

Я бы немного очистил ваш код, но только для удобства чтения:

var div = $("<div>").attr("id", "div-id").addClass("some-div");
var ul = $("<ul>").addClass("some-ul");
$.each(results, function(index) {
    var li = $("<li>").html(this).attr("id", index);
    ul.append(li);
});
div.append(ul);

// you haven't touched the DOM yet, everything thus far has been in memory

$("body").append(div); // this is the only time you touch the DOM
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...