Оптимизация JavaScript часть 1: Добавление элементов DOM в документ

Многие Веб-разработчики пишут горы кода на JavaScript, особенно в новом веке Web 2.0. Это мощная технология, но большинство браузеров содержат очень медленную реализацию движка, и многим в какой-то момент приходится пересматривать код и пытаться сделать его быстрее. В этой заметке я поделюсь своим опытом и покажу несколько трюков, которые помогут сделать Ваш код JavaScript таким быстрым, насколько это возможно.
Это первая статья из серии, будьте на связи.

Сценарий: Вы разрабатываете мощное приложение для Интернет, и Вам нужно динамически загрузить элементы, используя AJAX, добавив их в текущий документ. По какой-то причине Вы не хотите (или не можете) использовать полностью сформированный HTML, и получаете данные в массив JavaScript.
Я знаю два классических способах выполнить такую задачу: создать элементы, используя метод document.createElement(), и склеить HTML в строку, присвоим ее свойству parentElement.innerHTML. Конечно, Вы можете комбинировать оба способа. Рассмотрим эти подходы более детально.
Классический способ (и в идеальном мире - лучший) - использовать DOM для манипуляций над элементами:
 
for (var i = 1; i <= 1000; i++) {
    var li = document.createElement('li')
    li.appendChild(document.createTextNode('Element ' + i));
    el.appendChild(li);
}

Не такая уж и плохая производительность. Internet Explorer 6 самый медленный - 1403 мс (но ведь это самый медленный браузер в мире, правда?), остальные же браузеры справились довольно шустро (63 - 328 мс). Ладно, но как насчет создания элемента DOM прямо из кода HTML?
 
for (var i = 1; i <= 1000; i++) {
    var li = document.createElement('<li>Element ' + i + '</li>');
    el.appendChild(li);
}

Работает значительно лучше в Internet Explorer 6 (1134 мс), но вообще не работает в других браузерах. Блин! Конечно, Вы можете добавить блок try/catch и создать элементы, используя первый подход в блоке catch для остальных браузеров. Но у меня есть решение получше.
 
Every DOM node has attribute innerHTML which holds all child nodes as HTML string.
 
el.innerHTML = '';
for (var i = 1; i <= 1000; i++) {
    el.innerHTML += '<li>Element ' + i + '</li>';
}

Вау, я сильно удивлен, насколько медленной может быть процедура добавления элементов (11391 - 307938 мс)! Забавный результат, не правда ли? А все оттого, что браузеры пытаются отрисовать список после каждого обновления, и это сильно замедляет работу. Небольшая оптимизация:
 
var html = '';
for (var i = 1; i <= 1000; i++) {
    html += '<li>Element ' + i + '</li>';
}
el.innerHTML = html;

Все браузеры показали отличный результат (31 - 109 мс), но Internet Explorer по-прежнему медленный - 10994 мс. Я нашел решение, которой работает очень быстро во всех браузерах: создать массив кусков HTML, и затем склеить его используя пустую строку в качестве разделителя:
 
var html = [];
for (var i = 1; i <= 1000; i++) {
    html.push('<li>Element ');
    html.push(i);
    html.push('</li>');
}
el.innerHTML = html.join('');

Это самый быстрый подход для Internet Explorer 6 — 400 мс, и довольно быстрый для остальных браузеров (31 - 125 ms). Почему я не говорю “самый быстрый” в случае с Firefox? Я добавил еще пару примеров, чтобы разъяснить ситуацию:
 
var html = '';
for (var i = 1; i <= 1000; i++) {
    html += '<li style="padding-left: ' + (i % 50) +
    '" id="item-' + i + '">Element ' + i + ' Column ' +
    (i % 50) + '</li>';
}
el.innerHTML = html;
И второй пример:
var html = [];
for (var i = 1; i <= 1000; i++) {
    html.push('<li style="padding-left: ');
    html.push(i % 50);
    html.push('" id="item-');
    html.push(i);
    html.push('">Element ');
    html.push(i);
    html.push(' Column ');
    html.push(i % 50);
    html.push('</li>');
}
el.innerHTML = html.join('');

Вот результаты в виде таблицы и диаграммы.
 
No Method IE 6 IE 7 FF 1.5 FF 2.0 Opera 9
1 createElement() 1403 219 166 328 63
2 createElement() full 1134 - - - -
3 innerHTML 39757 20781 41058 307938 11391
4 innerHTML optimized 10994 46 50 109 31
5 innerHTML/join 400 31 47 125 31
 
6 innerHTML/optimized+ 28934 109 84 172 62
7 innerHTML/join+ 950 78 110 189 62
 

Выводы

  • Всегда используйте методы DOM, чтобы Ваш код соответствовал стандартам. Этот подход имеет удовлетворительную производительность и работает во всех браузерах.
  • Если Вам нужна самая высокая скорость, используйте подход join+innerHTML, который является самым быстрым в данном тесте.
  • Никогда не добавляйте строки HTML к innerHTML (даже если Вам нужно добавить маааааааленький элементик).
  • Opera - самый быстрый браузер в мире, но Internet Explorer 7 тоже довольно шустр, а вот Firefox 2.0 удивил своей низкой производительностью.
  • Никогда не верьте фанатикам вроде меня, и замеряйте производительность разных подходов сами (но не переживайте, Microsoft не проплатили мне рекламу своего браузера).

Только авторизованные пользователи могут оставлять комментарии

Чтобы оставить комментарий Вам нужно Зарегистрироваться или Войти в систему