Читать «Разгони свой сайт» онлайн - страница 89
Николай Мациевский
Для проверки видимости элемента принято проверять значение стиля display или наличие класса hide. Когда мы пишем функцию скрытия/отображения сами, то знаем, какое значение стиля display у объекта по умолчанию или какой класс какому состоянию соответствует. Однако универсальная (библиотечная) функция знать об этом не может.
offsetHeight и style.display
Проведем тестирование скорости вычисления значений offsetHeight и style.display.
Для удобства профайлинга вынесем доступ к этим значениям в отдельные функции:
function fnOffset(el)
{
return !!el.offsetHeight;
}
function fnStyle(el)
{
return el.style.display=='none';
}
где el — тестовый контейнер.
Проведем тест на тысяче итераций, на каждой итерации будем добавлять в тестовый контейнер элемент <span>. Проверим время, затрачиваемое на добавление тысячи элементов, без вызова тестовых функций тест clean. Проведем тестирование во всех браузерах, замеряя время следующим способом:
var time_start=new Date().getTime();
/* ... тест ... */
var time_stop=new Date().getTime();
var time_taken=time_stop-time_start;
где time_taken — это время, затраченное на тест, в миллисекундах.
IE sp62
IE8b
Firefox 2.0.0.12
Opera 9.22
Safari 3.04b
clean
128
153
15
15
16
offsetHeight
23500
10624
4453
4453
5140
style.display
171
209
56
56
34
height vs. style
140 раз
50 раз
80 раз
80 раз
150 раз
Судя по результатам тестов, доступ к offsetHeight медленнее в 50-150 раз.
Получается, что по отдельности и offsetHeight, и добавление элементов работают быстро, а вместе — очень медленно. Как же так?
Немного теории
Reflow — это процесс рекурсивного обхода ветви дерева DOM, вычисляющий геометрию элементов и их положение относительно родителя. Начало обхода — изменившийся элемент, но возможно и распространение в обратном порядке. Существуют следующие типы reflow:
начальный — первичное отображение дерева;
инкрементный — возникает при изменениях в DOM;
изменение размеров;
изменение стилей;
«грязный» — объединение нескольких инкрементных reflow, имеющих общего родителя.
Reflow делятся на неотложные (изменение размеров окна или изменение шрифта документа) и асинхронные, которые могут быть отложены и объединены впоследствии.
При манипулировании DOM происходят инкрементные reflow, которые браузер откладывает до конца выполнения скрипта. Однако исходя из определения reflow, «измерение» элемента вынудит браузер выполнить отложенные reflow. Т.к. возможно распространение снизу вверх, то выполняются все reflow, даже если измеряемый элемент принадлежит к неизменившейся ветви.
Операции reflow очень ресурсоемки и являются одной из причин замедления работы веб-приложений.
Если судить по тесту clean, все браузеры хорошо справляются с кэшированием многочисленных reflow. Однако запрашивая offsetHeight, мы «измеряем» элемент, что вынуждает браузер выполнить отложенные reflow. Таким образом, браузер делает тысячу reflow в одном случае и только один — в другом.