Pull to refresh

data:URI и производительность, или как замедлить Firefox в 10 (десять) раз

Reading time5 min
Views2.6K
Собственно, из заголовка должно быть почти все понятно. Но картинка не очень в тему: на ней надо нарисовать Лису, ползущую вслед догоняющему IE.

Это пост является ответом на «За бугром», ибо нашлась пара свободных часов, и было, чем их занять.

UPD Был обнаружен плагин — Wappalyzer — который на порядок замедлял отображение data:URI в Firefox. Но даже с его отключением Firefox продолжает проигрывать почти всем браузерам.

Но все по порядку.

Предыстория


Несколько месяцев назад ко мне в скайп постучался какой-то американец (с русским именем вроде) и спросил, что я знаю про последние оптимизации от Yahoo! (ну, те, где они data:URI наконец внедрили) и особенно про производительность data:URI. Я сказал, что, наверное (поскольку data:URI — это картинка в base64), последние несколько медленнее работают, чем обычные фоновые картинки, и вроде как должны подтормаживать.

Я быстро собрал предварительное окружение и через полчаса выдал предварительные результаты: data:URI тормозят, но иногда — очень сильно тормозят. Мне самому такой расклад показался подозрительным, поэтому я задвинул идею до лучших времен. И вот они настали :)

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


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

Отлично. В итоге у нас есть «локальная» страница (после первого запроса к странице закрывают вкладку с ней, открываем новую вкладку и открываем в ней исходную страницу: это создает необходимую «чистоту» для эксперимента), которая отображается в браузере с жесткого диска. После этого время рендеринга будет (на 99%) зависеть от особенностей браузера, а не от скорости получения ресурсов.

Дополнительно, естественно, все тесты прогонялись по 10 раз. 3-дельта выбросы не брались в расчет. В итоге общая точность не меньше 10% (т.е. все, скорее всего, погрешность 3-5%).

Тест первый: картинки против фона


Когда-то давно существовали рекомендации против использования обычных картинок. Рекомендовалось все в фоновых изображениях делать. Это не так (результаты отображения закэшированной страницы в мс).
Тест Chrome2 Fx3.5 Opera10 IE8 IE6/7
«Чистые» картинки 33 10 52 189 182
Фоновые картинки 124 11 47 181 130

Как мы видим, «оторвался» только Chrome (Safari в расчет не брался из-за дико оптимизированных таймеров, которые срабатывают «слишком быстро»), но на фоне основных браузеров это незаметно.

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

Тест второй: производительность data:URI / mhtml


Едем дальше. Помним, что data:URI поддерживается только IE8, для IE6/7 нужно использовать mhtml. Дополнительно IE8 не поддерживает картинки, большие 24 Кб. Поэтому в таблице для IE результаты mhtml, для остальных — data:URI.
Тест Chrome2 Fx3.5 Opera10 IE8 IE6/7
data:URI и mhtml 56 162 70 225 442

Уже здесь заметны «некоторые тормоза». Для Firefox рендеринг одних и тех же картинок обошелся вообще в 10 раз тяжелее. Но мы же рассматриваем применением этих техник для фоновых изображений? А для них:
Тест Chrome2 Fx3.5 Opera10
фоновые картинки в data:URI 83 155 69

Общая тенденция, как видим, сохраняется. Но это еще не все

Вывод: data:URI тормозит в Firefox, mhtml тормозит в IE.

Тест третий: производительность большого количества data:URI / mhtml


Внимательные читатели уже давно заготовили вопрос: что же нам показывают одни и те же неправдоподобно большие картинки. На «реальных» же сайтах все по-другому! Спешу их разочаровать: CSS Sprites размером 1000 на 1000 пикселей (миллион квадратных пикселей) встречаются не так редко. В среднем, на каждом сайт 5-20% области страницы занимают фоновые изображения. На разрешении 1200х1024 это примерно от 60 до 250 тысяч квадратных пикселей (т.е. всего в 3-10 раз меньше исходных изображений).

Но чего там дело встало, давайте возьмем 80 различных изображений (общей площадью 160 тысяч пикселей) и посмотрим, как браузеры из отрисовывают. А вот так (IE8 использует data:URI):
Тест Chrome2 Fx3.5 Opera10 IE8
много картинок в data:URI 65 105 85 99

Что-то напоминает, правда? Да, мы уменьшили суммарный размер изображений в 4 раза, но при увеличении числа объектов в 40 раз (с 2 до 80) ситуация, практически, повторилась. На реальных страницах несколько десятков, порой и пара сотен фоновых изображений. Т.е. наши тесты все ближе и ближе к реальности.

Вывод: медленный рендеринг base64 зависит не только от размера области, но и от числа объектов.

Тест четвертый: лицом к лицу лица не увидать


Но и тут опять имело место небольшое лукавство: ведь мы не знаем, как поведут себя браузеры, если увидят такое же количество обычных картинок на странице — как они будут «тормозить» в этом случае? С этой целью было собрано еще 2 идентичных окружения. Для каждого использовалось 2 различных изображений и 10 объектов, вырезающих из них фон.
Тест Chrome2 Fx3.5 Opera10 IE8 IE6/7
фоновые картинки 124 24 63 166 131
фоновые картинки в data:URI 41 140 73 - -

Для IE6/7/8 можно экстраполировать результаты, полученные из mhtml-страниц, либо пересобрать окружения с mhtml фоновыми картинками. Но основные результаты можно сказать уже сейчас.

Берем статистику использования браузеров, множим доли браузеров на относительное ускорение при использовании CSS Sprites (т.е. фоновых картинок) против data:URI / mhtml-подхода. Получаем цифру в 100мс для нашей суммарной области в 5*670000 = 3,35 миллиона пикселей (и 10 объектов). Для «среднего» сайта с 50 объектами с фоновыми изображениями и 100 тысячами пикселей в суммарной области мы получим порядка 15мс задержки при отображении каждой страницы (не важно, какое количество ресурсов находится в кэше браузера, сетевые задержки уже отыграли свое). Если у нас будет несколько сотен объектов с фоновыми изображениями, и общая область в миллион пикселей (например, какой-либо сложный веб-интерфейс), то средняя задержка для пользователей может вырасти до полусекунды и более. Такие вот пироги.

Вывод: data:URI + mhtml может существенно тормозить.

Что делать?


Все было бы неплохо, если Firefox и IE позаботятся о быстром рендеринге страниц и смогут отображать base64-данные так же быстро, как и обычные картинки. В этом случае использование множества base64-изображений будет, в общем случае, не хуже, чем CSS Sprites. Сейчас же наиболее оптимальным выходом является предварительное использование CSS Sprites, а потом конвертации минимального числа изображений в base64-формат, таким образом все издержки будут сведены к минимуму.

P.S. Если кому-то уж очень не нравятся фотографии на тестовых страницах — скиньте, пожалуйста, ссылки на любые подходящие по размеру — заменю. Просто ничего больше под рукой не было :)

P.P.S. Все расчеты в данной заметке оценочные. Они призваны показать только «слабые места» изображений в base64-формате, а не дать четкий алгоритм расчета, когда их можно использовать, а когда нет.
Tags:
Hubs:
+35
Comments48

Articles

Change theme settings