Pull to refresh

Comments 59

Век живи — век учись. Спасибо, не знал такого способа.
Сделайте, пожалуйста, наглядное сравнение производительности пары плохих вариантов из начала статьи и правильного. Очень удобно было бы посмотреть такой тест через сервис jsperf.com
и еще пример построения и вставкой dom цикле и второй вариант — с использованием documentFragment, чтобы на лицо было видно его большое преимущество. Перестроение DOM при изменении геометрических свойств — самая ресурсоемкая операция, поэтому никаких append в цикле.
Будет работать немного медленней, но не ощутимо для пользователя. Хотя опять же таки, смотря сколько у Вас в целом js кода и количество данных.
По поводу ваших созданий таблиц читаем "jQuery изнутри — парсинг html":

Для случая с <td>Привет!</td>, код превратится в <table><tbody><tr><td>Привет!</td></tr></tbory></table>, а указатель на контейнер с нужным нам результатом будет смещен на глубину в 3 тега, то есть в <tr> вместо <div>, который был создан внутри safeFrag в самом начале


Да и вообще лучше почитать всю серию «jQuery изнутри». Там много описано на эту тему и, в основном, более корректно и полно.
Да что ж такое, в третьем посте подряд создают DOM-дерево руками. Неужто времени не жалко?
Строить DOM создавая отдельно каждый элемент — это удар по производительности.
Первый пример из статьи будет работать в 10-100 раз быстрее, особенно в цикле.
Конечно так складывать строчки не очень красиво, зато работает быстро.

Ну и конечно никто не запрещает использовать шаблоны для построения DOM, хотя бы тем же jQuery.tmpl
А по моему все эти мудреные цепочки и вложенные методы jquery читаются хуже, чем старое доброе сложение строчек в цикле. +)
Быстрее будет не складывать строчки, а складывать их в массив и потом join-ить:
var html = [];
for (var i=0; i<100; i++) {
  html.push('<div>');
  html.push(i);
  html.push('</div>');
}
$('#div').append(html.join(''));

Операция join быстрее срабатывает, чем множество +
Только если говорить об IE. Разница между склеиванием массива и конкатенацией во всех более мение новых браузерах не настолько велика. Хотя да, отрабатывать будет чуть быстрее. Жаль что в javascript нет своего string builder-а
Операция join быстрее срабатывает, чем множество +

пруф
jsperf.com/concat-vs-join444 — только если так. Вот только добавление элемента в массив операция даже более ресурсоемкая нежели конкатенация строк. Так что если делать все так как рекомендует lexxpavlov, то производительность в современных браузерах (в случае сборки шаблона) упадет в разы.
Давайте глянем полный пример:
jsperf.com/concat-vs-join444/2

В хроме однозначно быстрее конкатенация чем даже джоин уже готового массива. Я уж молчу о том, что массив сначала просто необходимо наполнить.

В остальных браузерах однозначно имеет смысл конкатенировать, а не джоинить.
И правда, потестил сейчас оба варианта. Конкат быстрее оказывается.
Странно, потому что читал о таком способе и там убеждали в быстроте join, и тесты приводили. Я тогда не проверил сам, но запомнил. Извиняюсь, что привёл непроверенную информацию…
Кстати, интересно, что по тестам jsperf.com/concat-vs-join444/2 в некоторых браузерах join всё-таки быстрее. Но в остальных браузерах настолько медленнее, что небольшое превосходство в некоторых браузерах не окупится.

Вот мой тест: jsperf.com/concat-vs-join445
Интересно то, что при повышении объема данных join становится хуже и хуже…
Вам следует указать в статье, что такой способ создания элементов черезвычайно ресурсоемкий, и подходит только для создания небольшого количества элементов, и уж точно его нельзя использовать в цикле, раз уж ваша статья предназначена для новичков.
Дописал, спасибо.
Простите
Сложно сказать хороший это код или нет, но он явно недружелюбный.

Это на правах шутки?
Простите, а зачем, если есть вполне отличные шаблонизаторы? Тот же mustache, dust.js и иные.
В куче такого кода через два месяца не разберешься.
1) Да, jQuery позволяет так делать, но как минимум этого не стоит делать.
2) используйте хотя бы createDocumentFragment для сборки всего этого добра. как показывают бенчмарки — все это добро ускорится в разы.
3) Метод с конкатенацией строк отрабатывает в десятки раз быстрее.

Статья имеет смыл только в качестве пособия о возможностях jQuery, Использовать ЭТО в реальных проекта крайне не рекомендуется. Лучше уж использовать какие-нибудь шаблоны.
Еще стоит отметить, что использовать each для обхода массива (в примере с таблицей и списками) более ресурсоемкая операция чем:

for (var i = 0, l = arr.length(); i < l; i++) {
    ...
}


При этом кода не становится больше, а воспринимается он гораздо легче.
ИМХО пример с таблицей вообще ужасен.
Ну статья о jQuery. Если писать все на чистом js все будет быстрее и это очевидно. Если Вам не нравится, не пользуйтесь.
Да дело не в тормознутости jQuery, дело в неверном подходе.

На чистом js это будет что-то вроде:
var table = document.createElement('table')
var thead = document.createElement('thead')
var tr = document.createElement('tr')
var td = document.createElement('td')
var text = document.createTextNode('текст')
td.appendChild(text)
tr.appendChild(td)
thead.appendChild(tr)
table.appendChild(thead)

за корректность не ручаюсь, но в таком духе. Прямо как в известном диалоге: открыла чемодан, достала сумочку, закрыла чемодан, открыла сумочку, достала кошелёк, закрыла сумочку, открыла чемодан, положиле сумочку, закрыла чемодан, открыла кошелёк…

Как вам тут уже правильно заметили, написать
<table><thead><tr><td>текст</td></tr></thead></table>
и позволить браузеру распарсить это и построить дерево самому — значительно проще и понятнее, работает в десятки раз быстрее, чем если это делать на js, особенно для большого числа элементов.
Суть в том что кто-нибудь напишет «а вот как можно делать» а потом впечатлительные люди и вправду станут так делать. А потом сиди и рефактори за них.
Вы правы, я даже с Вами согласен, но я не думаю что оно работает настолько медленно что бы так критиковать. Если брать даже очень большие проекты на чистом js — они все равно будут немного тормозить, так как в этом весь javascript, небольшие задачи он решает очень неплохо, даже вот такими методами.
Оно работает именно «настолько медленно». В сложном интерфейсе, когда динамически подгружается десяток блоков со сложной версткой вы сразу почувствуете лаги, если не использовать шаблоны, data-binding, и прочие прелести современных фреймворков (knockout, backbone, angular).
Посмотрите как устроен любой сложный клиентский интерфейс, VK, Twitter и т.д

Все сообщество веб-разработчиков бьется за каждую миллисекунду и мгновенную отзывчивость интерфейса, а вы предлагаете самый худший вариант создания dom-дерева, отсюда и критика.
jsperf.com/dom-gen — как-то так… Код не оптимален, буду рад если кто-то скажет как написать последние 2 теста правильно. Я увы давно на старом добром JS Этого не делал.
С увеличением объема (скажем не простенький списочек а здоровый кусок шаблона) разница будет только увеличиваться.
То есть вы считаете что фанаты jQuery даже массив обходят при помощи each? Даже если объем кода увеличивается?
У вас лишние скобки после length :).
Точно :) Но поправить уже не могу.
а еще быстрее будет
for (var i = arr.length(); i--; )

это конечно для перебора, если нам не важен порядок.
Это уже экономия на спичках. Тогда уже можно было бы использовать Array.map
var element = document.createElement(tagName);
Ексть еще интересный способ динамического создания элементов, основным преимуществом которого является удобная поддержка с точки зрения взаимодействия с верстальщиком.

Идея: скрытый элемент в HTML-коде, затем через clone() получается его копия и уже в нее через селекторы вставляются нужные значения. Эдакий «шаблонизатор для бедных», когда по каким-то причинам настоящий шаблонизатор не используется.

<div class="myclass tpl hidden">
      <h1></h1>
</div>
...
<div id="parent"></div>


var tpl = $('.tpl').clone();
tpl.removeClass('hidden tpl');
tpl.find('h1').text('Hello!');
tpl.appendTo('#parent');


Есть и минусы, конечно. Например, наличие в коде лишнего элемента может дать погрешность, если в примере выше потребуется посчитать все элементы с классом myclass — нужно быть внимательным. Плюс — никаких тэгов в джавасрипте.
В общем-то clone даже не особо нужен, что мешает сразу нужную разметку вставить и скрыть ее до тех пор, пока она не понадобится?
В этом частном случае — да, но, как правило, подобным способом динамически создаются повторяющиеся элменты списка, строки таблицы либо целые однотипные блоки. Т.е. шаблон не должен исчезать.
Попробуйте запустить свой «Вот еще интересный вариант:», осознайте, что он на самом деле вставит в DOM.
Тогда к чему слова «Сложно сказать хороший это код или нет»? Этот код явно делает не то, что думал человек, написавший его.
«Статья рассчитана на начинающих», а вы оставляете такое без явного комментария о том, что такой код писать не надо.
Дописал, прошу прощение что ввел в заблуждение.
Как это вас извиняет? Топик-то ваш.
Для меня самым не очевидным в jQuery оказался тот факт, что обработчики событий «наслаиваются» друг на друга. То есть на элемент #id событие $('#id).click() может повесится несколько раз, и автоматически не перезаписываются.
Конечно, unbind меня спас. Но сам факт хранения где-то в памяти богом забытого обработчика для элемента — смущает
Возможно я открою для вас секрет, но обработчики событий в jQuery навешиваются через стандартный eventListener браузера. И фишка событий в Dom в этом и состоит, что события наслаиваются и всплывают. Без этого нельзя было бы реализовать делегацию событий, без этого много чего пришлось бы реализовывать с костылями. Да и во всех других системах с Ui ивентов можно навесить столько, сколько угодно.
К слову, раз уж возникают вопросы…

jsfiddle.net/a6rsx/ — полное управление ивентами. Тобиш возможность контролировать порядок исполнения, временно отключать лишние ивенты и т.д.
OMG, вы сейчас серьезно?
Я так понял что вы изучали только jQuery а не JavaScript… Прочтите пару книг не о jQuery.
Что же столько негатива то, это был одним из моих первых опытов работы с DOM-моделью как таковой. Слышал о ней, читал, пробовал понемногу обращаться к элементам — но как оказалось раньше всё было довольно поверхностным. Я не говорю что наслаивание обработчиков это плохо, это всего лишь было для меня не очевидно, в отличии от перестроения модели при добавлении нового элемента, например.
По поводу наслаивания (я так понимаю вы о всплытии событий?) — есть дерево элементов. Как только произошел клик по одному из них, событие передается дальше, вниз по дереву, к основанию. так как (если не вдаваться в оформление) это логично — кликнул на блок, а он внутри другого блока, по нему выходит тоже кликнули, ну и т.д. до document.

То что можно навешивать много обработчиков одного события на один элемент — это уже мелочи.
Не совсем, я добавлял элемент из одной таблицы в другую с помощью .clone().after() и вешал на класс, который был у новой строки строки, событие $('.classname).onclick().
Проблема была в том, что для первого добавленного элемента, событие срабатывало 1 раз.
Для второго — два раза. Ну и так далее.

Поскольку при каждом новом добавлении элемента я вешал НОВЫЙ .onclick(), в добавок к старому.

Вы говорите немного о другом, вложенность по дереву меня не удивляет)
1) у метода clone есть параметр, который отвечает за сохранение навешанных событий у элемента.
2) логичнее в этом случае использовать делегирование событий.
Спасибо, буду знать. Но в моём случае объект, от которого наследовалась строка, обладал другим функционалом, и на наследуемый элемент в любом случае вешался новый обработчик.

Видимо, по-умолчанию наследование обработчиков выключено (не замечал лишних срабатываний).

А, ну да: withDataAndEvents (default: false)
Не совсем, я добавлял элемент из одной таблицы в другую с помощью .clone().after() и вешал на класс, который был у новой строки строки, событие $('.classname).onclick().

А зачем? Раз уж добавляли методом .clone().after(), то надо было сразу вешать .click()
Вот об этом не подумал. Действительно, так было бы гораздо лучше.
При работе с DOM ещё полезно знать, что jquery-селекторы, это, по сути, массивы — таким образом можно быстро достучаться до чистой дом-ноды и применить к ней нативные(и быстрые) методы:
$('#element')[0] == document.getElementById('element')
в данном контексте это не существенно.
Хорошо описаны возможности JQuery, но я бы делал это на чистом JS, по нескольким причинам:
1) Это быстрее
2) Я знаю как это делается на JavaScript
3) Я не смогу запомнить как это делает JQuery =)
1) очевидно но плохо поддерживается. Идеальный компромис — конкатенация строк или шаблонизаторы.
3) ну это вы преувеличиваете.
Sign up to leave a comment.

Articles