Многие Веб-разработчики пишут горы кода на 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 |
Рисунок 1. Тест производительности: Добавление элементов DOM в документ
Вы можете посмотреть тест и получить собственные результаты производительности здесь.
join
+innerHTML
, который является самым быстрым в данном тесте.innerHTML
(даже если Вам нужно добавить маааааааленький элементик).html.push
на html[idx++]
в последнем варианте (по Lecompte) позволяют выиграть до 50% в производительности (зафисировано для IE7)