Опубликован: 16.06.2010 | Уровень: специалист | Доступ: платный
Лекция 6:

Оптимизация структуры веб-страниц

< Лекция 5 || Лекция 6: 123456 || Лекция 7 >
Аннотация: В этой лекции речь пойдет о методах, направленных на более оптимальное (с точки зрения скорости загрузки) расположение и использование структурных элементов страницы: стилей, скриптов и других статических элементов.

5.1. Динамические стили: быстро и просто

В книге "Разгони свой сайт" уже затрагивалась тема быстрого добавления стилевых правил в исходный документ динамически, не затрагивая при этом стадию предзагрузки (когда у нас еще белый экран в браузере). В ней однако не был рассмотрен следующий вопрос: какой метод использовать для добавления массива CSS-пра-вил в сам HTML.


Естественно, что таких вариантов существует несколько, и дальше они все будут рассмотрены с точки зрения производительности в клиентском браузере.

5.1.1. Тестовое окружение

Поскольку скорость загрузки отдельного CSS-файла достаточно велика, а нам требуется рассмотреть, как его содержимое может повлиять на скорость его динамического применения к документу, — следовательно, нам нужны сотни или даже тысячи правил. В качестве отправной точки была опять взята главная страница Яндекса, стили которой были вынесены в отдельный файл и скопированы 10 раз. Это дало необходимую задержку (которая существенно больше погрешности, вносимой браузерами) и не сильно увеличило сжатый с помощью gzip файл.

5.1.2. XHR в <body>

Выполняется XMLHttpRequest к CSS-файлу, затем содержимое последнего вставляется через innerHTML в <body> документа. Случай был выбран просто как базовый, потому что большое число узлов в DOM-дере-ве делает такую операцию сразу менее эффективной, чем вставка в <head>. Да и стили внутри тела документа запрещены стандартами.

// чтобы не копировать всем известный код, запишем так:
var xhr = new XMLHttpRequest;
if (xhr) {
xhr.onreadystatechange = function() {
try {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
// вставим полученные данные прямо в <body>
document.body.innerHTML +=
'<style type="text/css">' + xhr.responseText +
'</style>';
}
}
} catch(e){}
};
xhr.open("GET", 'styles.css?'+Math.random(), true);
xhr.send(null);
}
Листинг 5.1.

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

Итак, для снятия времени применения CSS-правил использовалась следующая конструкция (которая запускалась сразу после обращения к внешнему файлу):

var start = new Date();
var _timer = setInterval(function(){
// находим известный элемент документа и проверяем,
// применились ли к нему стили
if (document.getElementById('neck').offsetHeight < 300) {
// сообщаем о применении
alert('CSS files loaded in '+(new Date() - start));
// убиваем таймер
clearInterval(_timer);
}
}, 10);
Листинг 5.2.

Конечно, на время загрузки влияют сетевые задержки. Для борьбы с ними (и не только) бралась серия из 15 замеров, и значения, превосходящие текущее среднее более чем в 2 раза, просто отбрасывались (для контроля 3-дельта-выбросов).

Все результаты приведены в конце раздела.

5.1.3. XHR в head

В этом случае код вставлялся уже в <head> и применялся ряд методов для разных браузеров (ибо не все хотели через innerHTML или innerText вставлять полученные данные).

var text = xhr.responseText;
var head = document.getElementsByTagName('head')[0];
var style = document.createElement('style');
style.type = 'text/css';
// для IE
if (style.styleSheet) {
style.styleSheet.cssText = text;
} else {
// для Safari/Chrome
if (style.innerText == '') {
style.innerText = text;
// для остальных
else {
style.innerHTML = text;
}
}
head.appendChild(style);
Листинг 5.3.

5.1.4. Быстрый XHR в head

В следующем варианте проверялось прямое добавление стилевых правил к innerHTML в <head> (для тех браузеров, которые это поддерживают). Оказалось, что это вариант даже медленнее, чем предыдущий.

Если осуществлять это относительно обычного HTML-документа, то DOM-дерево изменяется быстрее (в IE6/7), поэтому на данный момент в общем случае практикуется именно такой подход.

var text = xhr.responseText;
var head = document.getElementsByTagName('head')[0];
if (/WebKit|MSIE/i.test(navigator.userAgent)) {
var style = document.createElement('style');
style.type = 'text/css';
if (style.styleSheet) {
style.styleSheet.cssText = text;
} else {
style.innerText = text;
}
head.appendChild(style);
} else {
head.innerHTML += '';
}
Листинг 5.4.

5.1.5. DOM-метод

И, наконец, хит сезона. Добавляем новый файл стилей прямо в <head> при помощи DOM-методов.

var link = document.createElement('link');
document.getElementsByTagName('head')[0].appendChild(link);
link.setAttribute('type','text/css');
link.setAttribute('rel','stylesheet');
link.setAttribute('href','style.css');
Листинг 5.5.

5.1.6. Результаты

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

Таблица 5.1.
Браузер XHR в <body> XHR в <head> Быстрый XHR в <head> DOM
IE 6 482 379 342 335
IE 7 532 364 391 353
IE 8b2 370 326 301 284
FX 3 420 294 300 282
Opera 9 892 894 1287 764
Safari 3 - 308 286 296
Chrome - 349 335 367

5.1.7. Выводы

Как хорошо видно из таблицы, наиболее быстрым способом для динамического добавления стилей в документ являются DOM-методы почти во всех случаях. Для Safari/Chrome вставка через XHR и специальные методы оказываются быстрее (но не намного). Отдельно хочется отметить довольно медленную работу Opera в таких задачах: по возможности стоит избегать динамических стилей для этого браузера.

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

< Лекция 5 || Лекция 6: 123456 || Лекция 7 >
Ольга Артёмова
Ольга Артёмова

Доброго времени суток!

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

Сертификация: оптимизация и продвижение web-сайтов.

Ярославй Грива
Ярославй Грива
Россия, г. Санкт-Петербург
Ёдгор Латипов
Ёдгор Латипов
Таджикистан, Кургантепа