Онлайн библиотека PLAM.RU


  • 2.1. Насколько ресурсоемко архивирование HTML
  • Издержки на использование mod_gzip
  • Формализация модели
  • Набор тестов
  • Результаты тестирования
  • Пара слов о файловой системе
  • Что быстрее: gzip или канал?
  • Исследование степени gzip-сжатия и загрузки процессора
  • Окончательные выводы
  • Конфигурируем Apache 1.3
  • Конфигурируем Apache 2
  • 2.2. CSS и JavaScript в виде архивов
  • Статическое архивирование в действии
  • Проблемы для Safari
  • Конфигурируем Apache
  • Маленькие «но»
  • Два слова о nginx
  • 2.3. Все о сжатии CSS
  • Инструменты
  • Графические результаты
  • Выводы
  • Практический пример
  • 2.4. JavaScript: жать или не жать?
  • Инструменты и методика
  • Графические результаты
  • Промежуточные выводы
  • Есть ли жизнь после сжатия?
  • Скорость загрузки JavaScript-библиотек
  • Методы упаковки JavaScript
  • Вариант
  • Среднее время
  • Уменьшенный
  • 519.7214
  • Упакованный
  • 591.6636
  • Нормальный
  • 645.4818
  • Производительность загрузки JavaScript-библиотек
  • Инструментарий
  • Среднее время
  • jquery-1.2.1
  • 732.1935
  • dojo-1.0.1
  • 911.3255
  • prototype-1.6.0
  • 923.7074
  • yahoo-utilities-2.4.0
  • 927.4604
  • protoculous-1.0.2
  • 1136.5497
  • Инструментарий
  • Среднее время
  • yahoo-utilities-2.4.0
  • 122.7867
  • Jquery-1.2.1
  • 131.1841
  • prototype-1.6.0
  • 142.7332
  • dojo-1.0.1
  • 171.2600
  • protoculous-1.0.2
  • 276.1929
  • 2.5. PNG против GIF
  • Алгоритмы сжатия
  • Возможности PNG
  • Поддержка PNG в браузерах
  • PNG и проблема соответствия для фоновых CSS-изображений
  • Анимированные PNG: MNG против "PNG+"
  • Двигаемся к маленьким PNG
  • Полезные советы
  • 2.6. Разгоняем favicon.ico — это как?
  • Краткое описание формата
  • Боевое крещение
  • Оптимальные размеры
  • Палитра
  • Размер (в байтах)
  • 2 бита
  • 198
  • 4 бита
  • 318
  • 8 бит
  • 1406
  • 24 бита
  • 894
  • 32 бита
  • 1150
  • PNG — быть или не быть?
  • А если еще и сжать?
  • data:URI нас спасет?
  • Заключение
  • 2.7. Режем cookie
  • Оптимизируем размер, зону и время действия
  • Хостинг для компонентов без cookie
  • Глава 2. Уменьшение размера

    2.1. Насколько ресурсоемко архивирование HTML

    Архивирование (gzip-, deflate-сжатие) уже давно является наиболее известной техникой оптимизации. Однако применяют ее по-прежнему так же редко, как и 10 лет назад. Я постараюсь максимально подробно осветить проблемные аспекты использования сжатия на сервере и предложить возможные методы их решения.

    Сжатие веб-содержимого посредством gzip (GNU zip) — это довольно старая технология. Суть ее сводится к тому, что содержимое перед отправкой пользователю сжимается по известному всем алгоритму zip. Сама спецификация gzip описана в RFC1952 ( http://tools.ietf.org/html/rfc1952 ), версия 4.2 которой датируется маем 1996 года. На сегодняшний день все популярные браузеры и веб-серверы поддерживают сжатие посредством gzip.

    Издержки на использование mod_gzip

    Начиная с версии протокола HTTP/1.1, веб-клиенты указывают, какие типы сжатия они поддерживают, устанавливая заголовок Accept-Encoding в HTTP-запросе:

    Accept-Encoding: gzip, deflate

    Если веб-сервер видит такой заголовок в запросе, он может применить сжатие ответа одним из методов, перечисленных клиентом. При выдаче ответа посредством заголовка Content-Encoding сервер уведомляет клиента о том, каким методом сжимался ответ:

    Content-Encoding: gzip

    Переданные таким образом данные меньше первоначальных примерно в 5 раз, и это существенно ускоряет их доставку. Однако давайте рассмотрим следующий вопрос: как динамическое gzip-сжатие влияет на быстродействие сервера? Рентабельно ли включать mod_gzip/mod_deflate для высоконагруженных проектов? И в каких случаях архивирование лучше вообще не использовать?

    Формализация модели

    Для начала нужно было каким-либо образом установить издержки на само архивирование. Схематично эти накладные расходы можно представить примерно в следующем виде:

    gzip = чтение/запись на диск + инициализация библиотеки + создание архива

    Предполагается, что первые две составляющие не зависят от размера файла (в исследовании участвовали файлы от 500 байтов до 128 Кб), а являются более-менее постоянными (по сравнению с последним слагаемым). Однако, как оказалось, работы с файловой системой зависят от размера. Об этом чуть подробнее рассказывается ниже.

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

    gzip = FS + LI + K*size

    Здесь FS — издержки на файловую систему, LI — издержки на инициализацию библиотеки и любые другие постоянные издержки, зависящие от реализации gzip, а K — коэффициент пропорциональности размера файла увеличению времени его архивирования.

    Набор тестов

    Итак, для проверки гипотезы и установления истинных коэффициентов нам потребуется 2 набора тестов:

    Тесты на сжатие: для набора пар значений «size — gzip»

    Тесты на запись: для набора пар значений «size — FS»

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

    Для тестирования был взят обычный HTML-файл (чтобы условия максимально соответствовали реальным). Затем из него были вырезаны первые 500, 1000 ... 128000 байтов. Все получившиеся файлы на сервере сначала в цикле архивировались нужное число раз, затем открывались и копировались на файловую систему — с помощью встроенных средств ОС Linux (cat, gzip), чтобы не добавлять дополнительных издержек какого-либо «внешнего» языка программирования.

    Результаты тестирования

    Для сжатия был получен следующий график. Хорошо заметно, что для небольших файлов основные издержки вносятся работой с файловой системой, а не архивированием. Здесь и далее все времена указаны в миллисекундах. Проводились серии тестов по 10000 итераций.

    Рис. 2.1. График издержек на gzip-сжатие от размера файла

    Теперь добавим исследования по работе с файловой системой, вычтем их из общих издержек и получим следующую картину.

    Рис. 2.2. График издержек на gzip-сжатие и работу с файловой системой

    Издержки на открытие, запись, закрытие файла зависят в некоторой степени от размера, однако это не мешает нам построить модельную зависимость вычислительной нагрузки от размера файла (предполагая, что в данном диапазоне она линейна). В результате получим следующее (рис. 2.3).

    Рис. 2.3. График реальных и модельных издержек на gzip-сжатие

    Пара слов о файловой системе

    Вопрос: зачем нужны дополнительные тесты на производительность файловой системы, ведь уже есть характерное время, уходящее на gzip-сжатие определенных размеров файлов?

    Ответ: во-первых, любой веб-сервер и так берет файл из файловой системы и архивирует уже в памяти, а потом пишет в сокет. Это время уже учтено при установлении соединения с сервером до получения первого байта. Нам лишь нужно понять, насколько оно увеличится, если сервер произведет еще некоторые операции с данными в оперативной памяти.

    Во-вторых, не все серверы читают прямо с диска. У высоконагруженных систем и прокси-серверов (например, 0W, squid, nginx, thttpd) данные могут храниться прямо в оперативной памяти, поэтому время доступа к ним существенно меньше, чем к файловой системе. Соответственно, его и нужно исключить из полученных результатов.

    Что быстрее: gzip или канал?

    Модель хорошо аппроксимирует полученные данные, поэтому примем ее за основу для следующих вычислений. Нам нужно, на самом деле, установить, насколько процессорные издержки на сжатие превосходят (или, наоборот, меньше) издержек на передачу несжатой информации. Для этого мы построим ряд графиков, приняв за эталон полученные коэффициенты для однопроцессорного сжатия на Dual Xeon 2,8 ГГц.

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

    Итак, ниже приведены издержки на передачу дополнительного количества информации (в миллисекундах) для двух разных каналов (100 Кб/с и 1500 Кб/с) и двух разных серверов (280 МГц и 1 ГГц). Видно, что график для gzip на 1000 МГц идет практически вровень с передачей данных для канала в 1500 Кб/с (одна линия перекрывает другую).

    Рис. 2.4. Накладные издержки на сжатие и передачу информации для 100 Кб и 1500 Кб и 280 МГц и 1000 МГц

    Исследование степени gzip-сжатия и загрузки процессора

    Рассмотрим далее, насколько сильно издержки на gzip зависят от степени сжатия, и как их прогнозировать с учетом всех остальных параметров. Новая серия тестов была направлена на установление зависимости между степенью сжатия, процессорными издержками и уменьшением размера файла, чтобы на основе этих данных построить более точную модель, определяющую рациональность использования архивирования «на лету».Как и ранее, на сервере проводились серии тестов по 10000 итераций в каждом. Замерялось время работы gzip при различных степенях сжатия. Затем оно усреднялось по серии, и из него вычитались издержки на работу с файловой системой. Также замерялось достигнутое уменьшение размера файла. Для зависимости «процессорное время — степень сжатия» был получен следующий график. По оси абсцисс идет степень сжатия, по оси ординат — затраченное время (среднее по серии).Рис. 2.5. Издержки на gzip от степени сжатияДалее график эффективности полученного сжатия (в % от оригинального размера файлов) от степени сжатия.Рис. 2.6. Эффективность различных степеней gzip-сжатия

    Окончательные выводы

    Собственно, графики говорят сами за себя. Если у вас HTML-файлы в среднем больше 4 Кб, то появится ощутимый выигрыш для большинства пользователей при включенном gzip на сервере (даже если этот сервер находится на весьма «слабенькой» машине). В случае маленьких файлов и(ли) медленного в вычислениях сервера, стоящего, однако, на быстром канале, будет экономичнее не сжимать файлы.

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

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

    Конфигурируем Apache 1.3

    Давайте рассмотрим, как можно настроить некоторые серверы для выдачи текстового содержания в виде архивов. Ниже приведен участок конфигурационного кода для Apache 1.3, позволяющий подключить gzip-сжатие. Основные директивы даны с комментариями.

    <IfModule mod_gzip.c>

    # включаем gzip

    mod_gzip_on Yes

    # если рядом с запрашиваемым файлом есть сжатая версия с расширением .gz, то

    # будет отдана именно она, ресурсы CPU расходоваться не будут

    mod_gzip_can_negotiate Yes

    # используем при статическом архивировании расширение .gz

    mod_gzip_static_suffix .gz

    # выставляем заголовок Content-Encoding: gzip

    AddEncoding gzip .gz

    # выставляем минимальный размер для сжимаемого файла

    mod_gzip_minimum_file_size 1000

    # и максимальный размер файла

    mod_gzip_maximum_file_size 500000

    # выставляем максимальный размер файла, сжимаемого прямо в памяти

    mod_gzip_maximum_inmem_size 60000

    # устанавливаем версию протокола, с которой будут отдаваться gzip-файлы

    # на клиент

    mod_gzip_min_http 1000

    # исключаем известные проблемные случаи

    mod_gzip_item_exclude reqheader "User-agent: Mozilla/4.0[678]"

    # устанавливаем сжатие по умолчанию для файлов .html

    mod_gzip_item_include file \.html$

    # исключаем .css / .js файлы (о них подробнее в следующем разделе)

    mod_gzip_item_exclude file \.js$

    mod_gzip_item_exclude file \.css$

    # дополнительно сжимаем другие текстовые файлы

    mod_gzip_item_include mime ^text/html$

    mod_gzip_item_include mime ^text/plain$

    mod_gzip_item_include mime ^httpd/unix-directory$

    # отключаем сжатие для картинок (не дает никакого эффекта)

    mod_gzip_item_exclude mime ^image/

    # отключаем 'Transfer-encoding: chunked' для gzip-файлов, чтобы

    # страница уходила на клиент одним куском

    mod_gzip_dechunk Yes

    # добавляем заголовок Vary для корректного распознавания браузеров,

    # находящихся за локальными прокси-серверами

    mod_gzip_send_vary On

    </IfModule>

    Конфигурируем Apache 2

    Для Apache 2 описанные действия выглядят гораздо проще.

    # добавляем Content-Type для всех файлов с расширением .gz

    AddEncoding gzip .gz

    # включаем сжатие для HTML- и XML-файлов

    AddOutputFilterByType DEFLATE text/html

    AddOutputFilterByType DEFLATE text/xml

    # и для иконок (об этом чуть ниже)

    AddOutputFilterByType DEFLATE image/x-icon

    # выставляем максимальную степень сжатия (если возникнут проблемы с

    # серверной производительностью, следует уменьшить до 7 или 1)

    DeflateCompressionLevel 9

    # и максимальный размер окна для архивирования

    DeflateWindowSize 15

    # отключаем архивирование для «проблемных» браузеров

    BrowserMatch ^Mozilla/4 gzip-only-text/html

    BrowserMatch ^Mozilla/4\.0[678] no-gzip

    BrowserMatch \bMSIE !no-gzip !gzip-only-text/html

    # добавляем заголовок Vary для корректного распознавания браузеров,

    # находящихся за локальными прокси-серверами

    Header append Vary User-Agent

    # и запрещаем кэширование сжатых файлов для локальных прокси-серверов

    <FilesMatch .*\.(html|phtml|php|shtml)$>

    Header append Cache-Control private

    </FilesMatch>

    Полные оптимизированные конфигурации для указанных серверов приведены в восьмой главе.

    2.2. CSS и JavaScript в виде архивов

    Теперь давайте рассмотрим, каким образом лучше всего будет отдавать CSS- и JavaScript-файлы в архивированном виде. Для обеспечения корректного архивирования, по-видимому, наиболее общий подход будет заключаться в выполнении по порядку следующих пунктов:

    проверить, умеет ли клиент принимать файлы в формате gzip-encoded;

    обеспечить соответствующий вывод на стороне сервера через gzip-функции либо организовать это непосредственно через веб-сервер (например, Apache);

    настроить конфигурационные файлы (или .htaccess), чтобы обеспечить корректный Content-Type.

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

    Статическое архивирование в действии

    Есть способ обойтись просто парой строчек в конфигурационном файле (httpd.conf или .htaccess, первое предпочтительнее), если потратить пару минут и самостоятельно заархивировать все необходимые файлы. Предположим, что у нас есть JavaScript-библиотека jquery.js на сервере. Заархивируем ее в jquery.js.gz (при помощи 7-zip или любой другой утилиты, если в работе используется Windows). В итоге, должен появиться файл jquery.js.gz. Его нужно положить в ту же директорию на сервере, что и исходный файл.

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

    gzip jquery.js -c –n -9 > jquery.js.gz

    Опция –c создаст новый файл (перенаправляем поток вывода в jquery.js.gz), -n исключит имя файла из архива (оно там только лишние байты занимает), а -9 заставит использовать максимальную степень сжатия. Таким образом, мы получим минимально возможный архив из искомого файла.

    Проблемы для Safari

    В ходе реализации данного решения возникла маленькая, но досадная неприятность. Safari не умеет правильно обрабатывать файлы с расширением .gz: для этого браузера стили и скрипты не могут иметь такого расширения. Как же нам быть? Выход достаточно простой и очевидный.

    Нам нужно именовать все архивы стандартным образом, но при этом иметь неархивированную версию для обратной совместимости (например, с дополнительным суффиксом nogzip). Поэтому для подготовки файлов нам будут нужны две команды (jquery здесь используется только в качестве примера):

    cp $src/jquery.js $dst/jquery.nogzip.js

    gzip $dst/jquery.nogzip.js -9 –n -c > $dst/jquery.js

    где $src — директория, в которой хранятся исходные файлы, а $dst — финальная директория для публикации. Сначала мы копируем файл в финальное место дислокации, а потом его архивируем под «правильным» именем.

    Конфигурируем Apache

    Тесты под Konqueror показали, что этот браузер не понимает архивированных файлов (CSS и JavaScript), поэтому чтобы уберечь десятую долю процента посетителей от сердечного приступа (когда они увидят сайт без соответствующих стилей), стоит добавить его в этот набор правил. Аналогично и «старым» браузерам (которые явно указывают, что не понимают архивов) отдается неархивированное содержание.

    <IfModule mod_rewrite.c>

    RewriteEngine On

    # перенаправляем Konqueror и «старые браузеры»

    RewriteCond %{HTTP:Accept-encoding} !gzip [OR]

    RewriteCond %{HTTP_USER_AGENT} Konqueror

    RewriteRule ^(.*)\.(css|js)$ $1.nogzip.$2 [QSA,L]

    </IfModule>

    Вся вышеуказанная конструкция «обернута» условием наличия на сервере подключенного mod_rewrite. Если он отсутствует, то это сразу станет видно на заявленных браузерах (перестанут отображаться стили и отрабатывать скрипты). Иначе Apache просто не сможет запуститься, т. к. RewriteEngine не будет объявлен.

    Дополнительно к заявленной логике необходимо выставить ряд заголовков для отдаваемых файлов. В частности, Vary и Cache-control касаются локальных проксирующих серверов, которые не должны кэшировать эти файлы, а пропускать их дальше к пользователю, не обрезая при этом заголовок User-Agent (иначе наш сервер никак не узнает, можно ли отдавать архивированную копию файла или нет).

    <IfModule mod_headers.c>

    Header append Vary User-Agent

    # выставляем для всех css/js файлов Content-Encoding

    <FilesMatch .*\.(js|css)$>

    Header set Content-Encoding: gzip

    Header set Cache-control: private

    </FilesMatch>

    # сбрасываем Content-Encoding в том случае, если отдаем не архив

    <FilesMatch .*\.nogzip\.(js|css)$>

    Header unset Content-Encoding

    </FilesMatch>

    </IfModule>

    В итоге для всех файлов, которые мы отдаем как архивы, дополнительно объявляется Content-Encoding, а для их неархивированных копий этот заголовок сбрасывается. Чем и достигается полная работоспособность данного решения.

    Маленькие «но»

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

    Итак, финальный алгоритм действий (при наличии на сервере mod_headers; иначе лучше воспользоваться конфигурацией, приведенной в восьмой главе) должен быть следующим:

    Добавляем описанные выше инструкции (оба блока) в конфигурационный файл Apache или.htaccess

    Пакуем файлы (с помощью 7-zip или gzip) и кладем на место обычных (расширение у файлов должно остаться прежним, .css или .js). Например, если у нас есть файл anyname.css, то после упаковки получается файл anyname.css.gz; переименовываем его обратно в anyname.css и заливаем на сервер. Для gzip все немного проще:

    gzip -c -9 -n anyname.css > anyname.css.gz

    mv anyname.css anyname.nogzip.css

    mv anyname.css.gz anyname.css

    Рядом с сжатыми файлами кладутся файлы с расширением nogzip.css или nogzip.js, которые содержат неархивированные копии. Например, после заливки сжатого файла anyname.css нужно создать на сервере еще один файл anyname.nogzip.css, который является копией несжатого файла. Для gzip это копирование уже производится чуть выше второй строкой в листинге.

    Два слова о nginx

    Кто работал с этим сервером, наверное, уже подумали: есть же модуль ngx_http_gzip_static_module, который позволяет класть рядом с файлом его сжатую версию с дополнительным расширением .gz и забыть практически обо всех описанных проблемах (этот функционал присутствует и для Apache 1.3). К сожалению, минусом данного решения будет отключение сжатия для всех видов файлов у браузера, который не поддерживает хотя бы один (теряется гибкость настройки).

    Однако, на данный момент таких случаев — доли процента, поэтому если у нас проект с низкой или средней посещаемостью, указанный модуль (в совокупности с ngx_http_gzip_module) позволит преодолеть почти все «подводные камни». Подробная конфигурация для nginx и Apache приведена в восьмой главе.

    В третьей главе рассказывается, как данное решение можно расширить для сброса кэша на клиенте. Теперь же перейдем к более подробному рассмотрению методов сжатия CSS- и JavaScript-файлов — ведь это может быть не только архивирование.

    2.3. Все о сжатии CSS

    Проблема уменьшения CSS-файлов в размере действительно актуальна, и хотелось бы иметь результаты исследования конкретно для такой оптимизации. Они, собственно, и приведены ниже.

    В Интернете было найдено 5 различных инструментов для минимизации CSS-кода; далее ими обрабатывались несколько примеров, которые затем подвергались еще и архивированию. Результаты представлены в виде графиков.

    Инструменты

    CSSMin ( http://code.google.com/p/cssmin/ ). Библиотека проводит набор простейших замен в CSS-файле (удаляет ненужные символы) и склеивает его в одну строку.

    Minify ( http://code.google.com/p/minify/ ) . Библиотека, минимизирующая как CSS-, так и JS-файлы. Кроме того, она может склеивать несколько файлов в один, заменять относительные пути к фоновым картинкам на более короткие и самостоятельно отдавать кэширующие заголовки. В общем, не намного лучше предыдущей.

    YUI ( http://developer.yahoo.com/yui/compressor/ ). YUI-compressor (использовалась версия 2.2.5). Фактически, делает то же самое, что две предыдущих библиотеки.

    CSS Minifier ( http://www.artofscaling.com/css-minifier/ ). Автор разработал собственный алгоритм сжатия (после беглого анализа это оказалась несколько переработанная версия CSS Tidy), который, по его собственному утверждению, «жмет лучше всех». Это мы и проверим чуть дальше.

    CSS Tidy ( http://csstidy.sourceforge.net/ ). Проект по минимизации CSS-файлов с открытым исходным кодом. Имеет много настроек, перенесен на несколько языков и используется на нескольких ресурсах, которые предлагают инструментарий для минимизации CSS-файлов, например, на www.codebeautifier.com. Это наиболее широко распространенная версия минимизатора.

    В качестве исходных файлов брались таблицы стилей с некоторых достаточно активно посещаемых ресурсов. Каждый из них был подвергнут действию минимизатора (для Minifier дополнительно файл склеивался в одну строку; вероятно, это временный баг текущей версии), затем архивировался. Корректность минимизации не проверялась (с этим в некоторых особо агрессивных случаях могут быть проблемы: CSS Tidy с определенными настройками перегруппировывает селекторы, и часть логики теряется).

    Графические результаты

    Что изображено на графиках? Выведен выигрыш (в процентах) относительно несжатого файла (по оси ординат отложены проценты). По оси абсцисс отложены номера файлов. Данные упорядочены по общей степени сжатия.

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

    Рис. 2.7. Эффективность различных инструментов для минимизации CSS-файлов по сравнению с gzip

    При архивировании, однако, все минимизаторы ведут себя примерно одинаково.

    Рис. 2.8. Эффективность различных инструментов для минимизации CSS-файлов вместе с дополнительным архивированием по сравнению с gzip

    Для уточнения картины при архивировании минимизированного файла отдельно было выделено его преимущество относительно обычного архивирования.

    Рис. 2.9. Эффективность различных инструментов для минимизации CSS-файлов вместе с дополнительным архивированием, увеличенный масштаб

    Тут уже видно отчетливо, что CSS Tidy ведет себя в целом лучше остальных скриптов (хотя, за исключением редких случаев, выигрыш не превосходит 6% относительно обычного архивирования).

    Выводы

    Во-первых, gzip и так показывает хорошее сжатие (до 81%), поэтому в большинстве случаев можно пользоваться только им.

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

    В-третьих, замечен локальный выброс при файле небольшого размера. Он связан с тем, что gzip изначально его плохо сжал (вероятно, из-за маленькой исходной библиотеки слов), поэтому все минимизаторы показали себя на высоте. Однако файлы такого размера (порядка 1 Кб) стоит либо объединять с другими файлами (ибо тратить время на дополнительный запрос на сервер из-за такой мелочи не очень рационально), либо включить в сам HTML-файл. Так что данный выброс не стоит считать серьезным основанием для того, чтобы действительно использовать какой-либо минимизатор только из-за выигрыша в 3-4% от размера исходного файла.

    В-четвертых, получается, что библиотека, жмущая лучше всего, проигрывает более умеренной сопернице при дополнительном архивировании результата. В нашем случае Minifier уступает CSS Tidy.

    В общем, если мы не хотим дополнительно морочить себе голову, то можно просто архивировать CSS-файлы (в среднем выигрыш 79%) либо проводить простую «подчистку мусора» перед архивированием (в среднем выигрыш 82%). Если мы заботимся о количестве байтов, то стоит изучить действие CSS Tidy и Minifier (их прелесть заключается в алгоритме перегруппировки селекторов) и использовать их, либо разработать собственное приложение.

    Практический пример

    По сравнению с JavaScript, сжимать CSS относительно просто. В силу практически полного отсутствия строк, заключенных в кавычки (в основном пути и названия шрифтов), мы можем изничтожить проблемы обычными регулярными выражениями. Когда же мы действительно встречаемся со строкой в кавычках, то мы можем объединить множественные пробелы в один (так как мы не рассчитываем обнаружить их в количестве больше чем 1 в URL или названиях шрифтов). Простейший скрипт на Perl может обеспечить нам все необходимые преобразования:

    #!/usr/bin/perl

    my $data = '';

    open F, $ARGV[0] or die "Не получается открыть исходный файл: $!";

    $data .= $_ while <F>;

    close F;

    $data =~ s!\/\*(.*?)\*\/!!g;# удаляем комментарии

    $data =~ s!\s+! !g; # сжимаем пробелы

    $data =~ s!\} !}\n!g;# добавляем переводы строки

    $data =~ s!\n$!!;# удаляем последний перевод строки

    $data =~ s! \{ ! {!g;# удаляем лишние пробелы внутри скобок

    $data =~ s!; \}!}!g;# удаляем лишние пробелы и синтаксис

    # внутри скобок

    print $data;

    Осталось прогнать все наши CSS-файлы через этот скрипт, чтобы сжать их, например так:

    perl compress.pl site.source.css > site.compress.css

    Путем простых текстовых преобразований можно уменьшить общий объем передаваемых данных почти на 50% (конечный выигрыш очень сильно зависит от стиля кодирования; обычно будет получен менее впечатляющий результат), что обеспечит более быструю работу сайта для конечных пользователей в том случае, если gzip применить не удается.

    2.4. JavaScript: жать или не жать?

    Давайте рассмотрим далее сжатие JavaScript-файлов и проведем анализ всех наиболее известных средств статической минимизации JavaScript-кода. Нам нужно, по сути, ответить на три основных вопроса:

    Имеет ли смысл пользоваться каким-либо минимизатором JavaScript-кода?

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

    Если такого средства нет, то каковы критерии использования набора инструментов?

    Итак, с постановкой задачи разобрались. Теперь перейдем собственно к самим инструментам и графикам степени сжатия исходного кода при их применении.

    Инструменты и методика

    Всего удалось обнаружить 5 кардинально различных средств для минимизации JavaScript-файлов, которые могут работать как автономные приложения (в расчете на то, что их можно будет далее запускать по событию или по расписанию, ориентируясь, в общем, на автоматизацию процесса публикации файлов на production-сервере).

    JSMin ( http://www.crockford.com/javascript/jsmin.html ). Наиболее широко распространенный минимизатор, основывается на простых правилах, перенесен на множество языков, в том числе и на сам JavaScript.

    JavaScript::Minifier ( http://search.cpan.org/~pmichaux/JavaScript-Minifier-1.04/lib/JavaScript/Minifier.pm ). Отдельный «перловый» модуль, по степени сжатия очень близок к JSMin, однако генерирует отличный от первого синтаксис.

    Dojo ShrinkSafe aka Rhino ( http://dojotoolkit.org/docs/shrinksafe ). Первоначально разрабатывался как Rhino, затем был включен в состав Dojo. Запускается как JAR-модуль.

    Dean Edwards Packer ( http://dean.edwards.name/packer/ ). Достаточно широко известный инструмент от не менее известного Dean Edwards. Перенесен на некоторые языки, в том числе на PHP4/5.

    YUI Compressor ( http://developer.yahoo.com/yui/compressor/ ). В представлении также не нуждается — именно на его основе проведена оптимизация сайтов Yahoo. Для анализа использовалась версия 2.2.5. Запускается как JAR-модуль.

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

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

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

    Графические результаты

    Сами графики, собственно. Что на них изображено? Выведен выигрыш (в процентах) относительно несжатого файла (по оси ординат отложены проценты). По оси абсцисс отложены номера файлов. Данные упорядочены по общей степени сжатия.

    Все инструменты приведены на одном графике. Заметен явный выигрыш Packer без архивирования.

    Рис. 2.10. Эффективность различных инструментов для минимизации JavaScript-файлов вместе по сравнению с gzip

    При архивировании, однако, все минимизаторы кода ведут себя примерно одинаково.

    Рис. 2.11. Эффективность различных инструментов для минимизации JavaScript-файлов вместе с дополнительным архивированием по сравнению с gzip

    Для уточнения картины при архивировании минимизированного файла давайте отдельно выделим их преимущество (если оно имеется) относительно обычного архивирования.

    Рис. 2.12. Эффективность различных инструментов для минимизации JavaScript-файлов вместе с дополнительным архивированием, увеличенный масштаб

    Тут уже хорошо видно, что YUI Compressor ведет себя в целом лучше остальных скриптов.

    Промежуточные выводы

    Во-первых, стоит указать на практически идентичное поведение JSMin и JavaScript::Minifier — скорее всего, они действуют по достаточно похожему алгоритму. Однако последний обладает скрытым потенциалом (при более подробном рассмотрении файлов, полученных вследствие его работы, оказалось, что они могут быть уменьшены еще), но он работает в несколько раз дольше аналогов (3-5 секунд против 0,3-0,5 для Packer на PHP).

    Во-вторых, файлы, которые меньше 1 Кб или при архивировании дают выигрыш меньше 70%, минимизировать не имеет смысла. Минимизация в таком случае дает результат, сравнимый с нулем. Если с сервера отдаются небольшие (до 20 Кб в несжатом виде) архивированные файлы (.gz), то стоит по умолчанию их минимизировать с помощью JSMin.

    В-третьих, если на сервере не поддерживается сжатие скриптов, то отдавать лучше версию, минимизированную с помощью Packer, — в таком случае выигрыш будет довольно значительным (естественно, если размер файла больше 1 Кб). Такая минимизация в среднем показала 50%-ное преимущество относительно несжатого файла.

    В-четвертых, во всех остальных случаях (сервер отдает достаточно большие gzip-версии файлов, которые хорошо архивируются) стоит использовать YUI Compressor (в среднем показал 6%-ное преимущество относительно простого gzip).

    Есть ли жизнь после сжатия?

    Хочется отметить, что при минимизации JavaScript-файлов нужно следить за тем, чтобы функционал не уменьшился вследствие этой самой минимизации. Для проверки JS-файлов на работоспособность и общую адекватность существует проект JSLint ( http://jslint.com/ ), который сравнивает исходный файл с набором спецификаций по синтаксису и выдает сообщения об обнаруженных ошибках.

    Скорость загрузки JavaScript-библиотек

    В начале 2008 года командой PDWiki был проведен весьма впечатляющий анализ производительности JavaScript. Они собирались разобраться, насколько быстро грузятся JavaScript-библиотеки (естественно, скорость их загрузки будет заметно влиять на скорость загрузки всей страницы).

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

    Методы упаковки JavaScript

    При загрузке JavaScript-кода обычно предполагается, что чем меньше загружаемый файл, тем быстрее он загрузится. Это несколько не соответствует действительности, что прекрасно подтверждает дальнейшее изучение ситуации. Мы рассмотрим скорость загрузки библиотеки jQuery в трех формах: обычной, уменьшенной (при помощи YUI Compressor) и упакованной (используется Packer). Если упорядочить их по размерам, то будет примерно так: самый маленький вариант — естественно, упакованный, — затем уменьшенный, затем нормальный.

    Однако упакованная версия добавляет некоторые накладные расходы: ее нужно сначала распаковать (выполнять достаточно тяжелый eval и replace) с помощью того же JavaScript на стороне клиента. Эта распаковка может занять достаточно продолжительное время при загрузке страницы. То есть использование уменьшенной версии, в конце концов, будет значительно быстрее, чем упакованной — даже при достаточно большом размере файла. Ниже приводится сравнение времени загрузки различных вариантов уменьшения jQuery.

    Ниже приводится сравнение времени загрузки различных вариантов уменьшения jQuery.

    Вариант

    Среднее время

    Уменьшенный

    519.7214

    Упакованный

    591.6636

    Нормальный

    645.4818

    Таблица 2.1. Время загрузки библиотеки jQuery, которая была подвергнута различным уменьшениям

    Очевидно, что при использовании любой техники сжатия стоит помнить о такой формуле:

    Время_загрузки = Время_на_скачивание + Время_на_исполнение

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

    Подводя итог всем вышеприведенным выкладкам, можно сделать следующее заключение. Если использовать gzip-сжатие для текстовых файлов, то наилучшим выбором будет применение YUI Compressor для дополнительной минимизации CSS- и JavaScript-файлов. Результирующий файл будет в среднем самым маленьким из возможных вариантов сжатия и будет загружаться в браузере максимально быстро.

    Производительность загрузки JavaScript-библиотек

    Из этого исследования можно еще получить данные по влиянию производительности различных JavaScript-библиотек на загрузку страницы. Таким образом, более простая и меньшая по размеру библиотека будет загружаться быстрее аналогов. По результатам видно, что jQuery загружается достаточно быстро относительно других библиотек (200–400 мс — существенный выигрыш в скорости). Ниже приведено среднее время загрузки неархивированных и неуменьшенных версий библиотек не из кэша.

    Инструментарий

    Среднее время

    jquery-1.2.1

    732.1935

    dojo-1.0.1

    911.3255

    prototype-1.6.0

    923.7074

    yahoo-utilities-2.4.0

    927.4604

    protoculous-1.0.2

    1136.5497

    Таблица 2.2. Время загрузки различных библиотек (не модифицированные версии, без учета кэширования)

    Сейчас, конечно, можно возразить, что нечестно тестировать загрузку только некэшированных страниц, ибо, согласно исследованиям Yahoo по кэшированию, примерно 50% посетителей не будут иметь возможности кэшировать содержание страницы. Поэтому важно убедиться, что не только первоначальная, но и кэшированная версия страницы также загружается максимально быстро. Итак, ниже приведены цифры для загрузки архивированных и уменьшенных версий из кэша

    Инструментарий

    Среднее время

    yahoo-utilities-2.4.0

    122.7867

    Jquery-1.2.1

    131.1841

    prototype-1.6.0

    142.7332

    dojo-1.0.1

    171.2600

    protoculous-1.0.2

    276.1929

    Таблица 2.3. Время загрузки различных библиотек (модифицированные версии, с учетом кэширования)

    Если принять во внимание кэшированную версию, то разница становится уже не столь очевидна (всего 10-30 мс — за исключением Dojo/Scriptaculous). Более того, при загрузке из кэша все издержки приходятся на инициализацию библиотек — именно поэтому так важно знать и использовать принципы создания быстрых JavaScript-приложений. Об этом подробнее рассказывается в седьмой главе.

    Но давайте на этом закончим со сжатием текстовых файлов и перейдем к более интересным случаям — уменьшению в размере различных форматов изображений.

    2.5. PNG против GIF

    Переносимый сетевой графический формат (англ. Portable Network Graphics, PNG) разрабатывается как более эффективная, гибкая и свободная от патентов замена GIF-формату. PNG был задуман для хранения отдельных растровых изображений и дальнейшего их распространения по компьютерным сетям. PNG был создан в 1995 году в ответ на давление со стороны Unisys и их патента на алгоритм LZW-сжатия, используемый в GIF. Хотя срок действия патента Unisys уже закончился, причины на переход от GIF к PNG остались практически прежними. Заменив GIF-изображения теми же самыми, но в формате PNG, можно ускорить загрузку страниц и сэкономить трафик пользователей.

    Алгоритмы сжатия

    PNG использует алгоритм deflate-сжатия обычно со скользящим окном в 32 Кб. Deflate является улучшенной версией алгоритма сжатия Lempel-Ziv (LZ77), который применяется в zip- и gzip-файлах. Созданный Phil Katz для второй версии PKZip, deflate совмещает LZ77 с кодированием Huffman и является на 10-30% более эффективным, чем LZW, при сжатии без потери информации. Так же как и gzip, некоторые инструменты по PNG-сжатию предполагают опциональный параметр «степень сжатия», который варьируется от 1 до 9. По умолчанию выставляется 6. Практически всегда лучшим выбором для максимального сжатия является 9.

    Неудивительно, что изображения, сохраненные как PNG, обычно на 10-30% меньше по размеру, чем GIF, хотя в некоторых редких случаях они могут быть несколько больше (чаще всего это проявляется для небольших изображений). Обычно изображения с большими однотонными областями сжимаются лучше, чем градиентные с большим количеством переходов между цветами.

    Возможности PNG

    В PNG присутствует набор возможностей, которые делают его привлекательным для использования во многих отраслях, где требуется применение ограниченной палитры. Поддержка в PNG 16-битной серой шкалы прекрасно подходит для создания точных радиологических изображений. PNG предварительно фильтрует данные по конкретному изображению при помощи предсказательных функций. Одной из них является «Вверх» (англ. Up), которая ищет похожие наборы данных в вертикальных шаблонах для полноцветных PNG. PNG с индексированными цветами (8 битов или меньше) обычно не выигрывает от использования фильтрации, поэтому стоит использовать «Ничего» (англ. none), если есть возможность выбора. Для полноцветных или серых изображений лучше применять «Адаптивный» (англ. Adaptive) алгоритм.

    Как говорит Greg Roelofs, «PNG в основном используется для создания 24-битных изображений в RGB-палитре, например картин с рассчитанным освещением с минимальным числом текстур или математических объектов. Они все обладают искусственно сглаженными цветовыми переходами, которые хорошо сжимаются при помощи PNG-фильтров. Некоторые фракталы могут вести себя таким же образом, но у многих из самых лучших примеров имеется достаточно «зашумленных» областей, которые сжимаются весьма слабо».

    Для веб-страниц вполне можно использовать PNG8 (8-битный формат), с помощью которого дизайнеры могут заменить существующие GIF-изображения. У PNG также может быть альфа-значение для каждого цвета в палитре, которое фактически означает, что используется RGBA-палитра, а не RGB-XOR-маска, как GIF. Это позволяет варьировать прозрачность цвета в больших пределах, сохраняя преимущества 8-битного изображения перед 32-битным. PNG могут также содержать только один уровень прозрачности, совсем как GIF89a. Алгоритм сжатия PNG для повторяющихся горизонтальных шаблонов совпадает с LZW-сжатием в GIF.

    Многослойный PNG-файл также может быть отображен на экране по загрузке только 25% всего файла, в то время как GIF требует загрузки 50% размера перед распознаванием. За исключением весьма редких случаев замена GIF-изображений на PNG-эквиваленты способна существенно уменьшить их размер.

    Ниже приведены некоторые из возможностей PNG-формата.

    8-битные (индексированная палитра), 16-битные серые или 48битные полноцветные изображения.

    Градация альфа-прозрачности до 16 битов.

    Гамма-коррекция (хотя эта возможность может быть проблематичной).

    Улучшенный по сравнению с LZW алгоритм сжатия.

    Двумерная схема для многоуровневых изображений (Adam7).

    Метаданные (сжатые или несжатые).

    Формат, свободный от патентов.

    Поддержка PNG в браузерах

    В Netscape естественная поддержка PNG весьма ограничена: начиная с версии 4.04, для Internet Explorer она зависит от операционной системы. Для Macintosh IE полностью поддерживает PNG с версии 5.0 (в том числе включая альфа-канал). MSIE для Win32 и Unix обладает естественной поддержкой PNG (на деле же весьма посредственной) начиная с 4.0, но не поддерживает альфа-канал до версии 7.0 (это исправляется при помощи фильтра AlphaImageLoader).

    На данный момент большое количество разнообразных браузеров также поддерживает PNG, однако лишь с 1-битной прозрачностью, что позволяет использовать PNG для замены неанимированных GIF.

    PNG и проблема соответствия для фоновых CSS-изображений

    К несчастью, поддержка возможностей PNG-гаммы и цветовой коррекции не является кроссбраузерной. Наиболее часто рекомендуемой мерой для исправления возможных ошибок будет исключение фрагментов, обеспечивающих гамму и цветовую коррекцию, для создания «неименованного» PNG (удаление gAMA-чанка). Это решает проблему цветового соответствия для современных браузеров, кроме Safari под Mac до OS 10.4 (тут может помочь удаление sRBG-чанка; подробнее об удалении чанков рассказывается немного ниже).

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

    Анимированные PNG: MNG против "PNG+"

    Формат составной сетевой графики (англ. Multiple Network Graphics, MNG) представляет собой несколько PNG-изображений, по аналогии с GIF89a. Однако MNG-формат является более сложным и не поддерживается текущими браузерами (для этого нужно использовать бесплатное расширение libmng).

    Группа разработчиков Mozilla расширила текущий (для одного изображения) PNG-формат в браузере Firefox 3, добавив несколько дополнительных кадров для анимации. Существует также встречное предложение со стороны членов группы PNG, подразумевающее создание чего-то подобного; однако, не противоречащего спецификации PNG. Оба этих направления значительно проще, чем MNG, и оба открыты для голосования в группе PNG.

    Сейчас же для анимации изображений лучше всего применять GIF89a или Flash. Однако последние достижения в векторной графике, SVG и развитие анимационных JavaScript-библиотек составляют реальную конкуренцию указанным форматам. Вполне возможно, что через несколько лет вся несложная анимация в браузерах будет осуществляться при использовании именно такого подхода.

    Двигаемся к маленьким PNG

    PNG работает лучше с большими однотонными областями. Чтобы увеличить степень сжатия, стоит уменьшить количество «шума» в ваших картинках для увеличения размеров однотонных областей. Уменьшайте области размывания, хотя для изображений с градиентами размывание позволяет использовать меньшую глубину цвета. Избегайте сглаживания текста для уменьшения числа цветов, которые для него необходимы, в финальном изображении.

    По возможности уменьшайте число цветов в вашем исходном изображении, если в процессе разработки этот фактор можно контролировать. Стоит также избегать использования многослойных PNG-изображений для уменьшения размера файла, так как семипроходная многослойная схема может добавить от 20% до 35% к размеру PNG-файла. Наконец, можно применять специальное программное обеспечение для оптимизации PNG-изображений, которое специально разрабатывается с этой целью, например pngout или pngcrush.

    Полезные советы

    Ниже приведено несколько простых советов, как текущие изображения можно дополнительно уменьшить в размере. Можно написать простой скрипт, который перебирает директории с изображениями перед публикацией сайта и делает следующие действия (далее приведены примеры запуска утилит из командной строки для ОС Linux):Преобразовывает GIF в PNG (и проверяет, есть ли при этом выигрыш):

    convert image.gif image.png

    или так

    gif2png -nstO image.gif image.png

    Уменьшает PNG-файлы в размере:

    pngcrush –qz3 –brute image.png result.png

    если при этом нужно удалить и gAMA-чанк, то:

    pngcrush –qz3 –rem gAMA –brute image.png result.png

    если при этом хотим удалить другие чанки, отвечающие за цветовую коррекцию, то:

    pngcrush –qz3 –rem gAMA -rem cHRM -rem iCCP -rem sRGB \

    –brute image.png result.png

    Уменьшает JPEG-файлы в размере (без потери качества):

    jpegtran -copy none -optimize -perfect image.jpg > result.jpg

    Под Windows для уменьшения PNG-изображений можно использовать TweakPNG ( http://entropymine.com/jason/tweakpng/ ). Аналогом jpegtran является набор портированных утилит jpeg, которые можно загрузить по адресу: http://sourceforge.net/projects/gnuwin32/ .Для отдельно взятой страницы общий размер изображений может быть уменьшен на 20–30% только благодаря следованию этим простым советам.

    2.6. Разгоняем favicon.ico — это как?

    В очередной презентации Yahoo! на тему клиентской производительности (часть 2) был поднят вопрос о favicon.ico. Они приводили несколько интересных фактов о данном явлении и давали пару советов. Процитируем их рекомендации.

    www.mysite.ru/favicon.ico.

    Необходимое зло:

    браузер в любом случае ее запросит,

    лучше не отвечать 404-ошибкой,

    будут отправлены cookie,

    не может быть в CDN,

    мешается в последовательности загрузки ресурсов.

    Уменьшайте ее (<=1 Кб).

    Не стоит использовать анимированные иконки.

    Выставляйте заголовок Expires.

    Запросы к favicon.ico составляют 5-10% от общего числа запросов к сайту.

    favicon.ico, во-первых, запрашивается едва ли не один-единственный раз браузером при посещении сайта, во-вторых, загружается, игнорируя обычный порядок загрузки. Из чего можно заключить, что она не является обычной картинкой при загрузке сайта, поэтому в дополнение к уже имеющейся информации был проведен ряд дополнительных исследований, чтобы объединить все, что известно прогрессивному человечеству на данную тему. Однако в ходе изучения материала оказалось, что проблема совсем не так прозрачна, как представлялось изначально. Формат .ico предстал в новом свете, весьма выгодном для использования в Интернете.

    Краткое описание формата

    favicon.ico имеет формат .ico (на самом деле, такой формат есть, а соответствующий MIME-тип прижился не везде; при этом он объединяет несколько довольно специфических типов; подробнее можно посмотреть в статье на Wikipedia, http://en.wikipedia.org/wiki/ICO_%28icon_image_file_format%29 ). С одной стороны, он позволяет представлять информацию без потерь (в отличие от JPEG). С другой стороны, он фактически является аналогом BMP, но на этом их сходство заканчивается.

    Я не буду приводить точную его спецификацию (она не так сложна, и ее можно обнаружить, например, по следующему адресу: http://www.daubnet.com/formats/ICO.html ), однако в глаза сразу бросилось две вещи: возможность использования индексированных цветов (ага, это уже почти GIF) и возможность использования линейного сжатия (а это уже почти PNG). Интересно? Тогда мы продолжаем.

    Собственно, эта информация следует из вот этих частей формата:

    BitCount2 bytesbits per pixel = 1, 4, 8

    Compression4 bytesType of Compression = 0

    Боевое крещение

    После небольших поисков удалось собрать тестовое окружение под Firefox 3, использующее base64-кодирование картинки в виде .ico. Удалось сделать однотонное изображение (палитра 4 бита) размером в 318 байтов (против 894 стандартных; меньше почти в 3 раза). С палитрой в 2 бита возникли трудности под Safari, корректный результат получить не удалось, однако, возможно, его также можно использовать.

    Может быть, кому-то покажется, что 576 байтов — это очень мало. Но стоит заметить, что, во-первых, некоторые иконки используют фактически только 2 цвета, поэтому их можно сжать до еще меньшего размера. Во-вторых, при больших размерах (32x32, 48x48) выигрыш в процентах будет таким же. Т. е. иконки в 16 Кб можно будет спокойно уменьшить раза в 3–7. И это без учета вырезания неиспользуемых фреймов в них (ведь формат позволяет создавать анимированные иконки).

    Оптимальные размеры

    Путем нехитрых вычислений заголовков, смещений и палитр можно получить некоторые цифры для размера наиболее стандартных favicon.ico (размер картинки — 16x16 пикселей). Для 32х32 и 48х48 размер файлов должен увеличиться примерно в 4 и 9 раз соответственно.

    Палитра

    Размер (в байтах)

    2 бита

    198

    4 бита

    318

    8 бит

    1406

    24 бита

    894

    32 бита

    1150

    Таблица 2.4. Размер файла favicon.ico 16x16 в зависимости от используемой палитры

    Для динамических иконок можно смело множить размер одиночной иконки на число фреймов, ибо заголовок у всего файла всего 62 байта, основная часть — именно данные.

    PNG — быть или не быть?

    В Wikipedia указывается, что вместо .ico можно использовать .png как наиболее перспективный из форматов, применяемых для сжатия изображения без потери качества. При соответствующем объявлении файла в секции head страницы позади планеты всей у нас остается Internet Explorer, так что данный подход может быть рассмотрен только как альтернативный. Подчеркну, что в среднем размер PNG-файла с иконкой не сильно меньше, чем ICO, но можно совершить дополнительные телодвижения, подключив одну иконку для всех браузеров, а вторую — только для IE.

    А если еще и сжать?

    Если мы не можем адекватно использовать нормальные форматы (PNG, GIF) для представления favicon.ico, то почему бы не задействовать gzip-сжатие для ее выдачи клиентскому браузеру? Можно. И все актуальные браузеры это понимают. Размер при этом составляет порядка 300 байтов (уменьшается в 3 раза по сравнению с исходным).

    Повторюсь, речь идет о возможностях для уменьшения favicon.ico в целом, а не об абсолютных цифрах. Если у вас на сервере уже используется сжатие, просто добавьте туда компрессию для image/x-icon и забудьте о ней.

    data:URI нас спасет?

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

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

    Заключение

    Одним из наиболее спорных моментов в презентации Yahoo! было заявление о том, что favicon.ico «мешается» при загрузке страницы. Как можно судить по логам сервера при загрузке страницы, этот файл действительно запрашивается где-то в середине общего процесса загрузки, ориентировочно после CSS-файлов и до фоновых изображений, поэтому его оптимизация может оказаться одним из ключевых моментов для ускорения загрузки сайта в момент первого посещения (с пустым кэшем).

    Также ради простого уважения к пользователям (зачем им загружать лишние 10 Кб кода, который отрисуется у них в области 16x16 пикселей?) не стоит раздувать его размер без особой необходимости. Уважайте своих посетителей.

    2.7. Режем cookie

    В качестве заключительного аккорда при рассмотрении уменьшения количества передаваемых данных между сервером и клиентом нужно обязательно упомянуть cookie.

    Cookie являются одним из HTTP-заголовков, которые браузер посылает на сервер, а сервер вправе им ответить (если копнуть глубже, то существует пара заголовков: Cookie и Set-Cookie — но в данном случае это не так существенно). Общий размер HTTP-заголовков обычно не превосходит 500–1000 байтов, однако cookie могут существенно его увеличить (так как на них накладывается ограничение в 4 Кб).

    При объемах полезной информации в несколько Кб размер cookie может оказать критичное воздействие на скорость передачи данных. Давайте рассмотрим, какие существуют способы уменьшения этих издержек.

    Оптимизируем размер, зону и время действия

    В большинстве случаев пользователю просто не нужно пересылать огромные массивы данных каждый раз — для него вполне возможно ограничиться только сессионным ключом. Исходя из этого стоит пересмотреть логику использования заголовков cookie и оставить только действительно необходимые.

    Как вариант, можно устанавливать cookie только для определенных разделов на сайте либо ограничиваться только текущей сессией пользователя на сайте (которая не будет сохраняться при повторном заходе).

    Также у cookie можно варьировать срок действия, что будет несколько нивелировать их влияние, если пользователь будет заходить на сайт достаточно редко: с каждым новым заходом cookie из браузера пересылаться не будут, однако их будет отправлять сервер. Поэтому данная мера производительность особо не повысит.

    Хостинг для компонентов без cookie

    Для высоконагруженных проектов, которые активно используют cookie и стремятся минимизировать издержки от них, стоит рассмотреть вынос статических ресурсов на отдельный хост, для которого cookie вообще не будут устанавливаться.

    В данном случае можно рассмотреть использование поддомена (что может оказаться бесполезным, если cookie выставляются на *.domain.ru) или домена верхнего уровня (в таком случае придется регистрировать отдельный домен для хранения статических ресурсов). Однако в обоих случаях возможны проблемы с локальными прокси-серверами: они могут отказаться кэшировать файлы с физически разных доменов.









    Главная | Контакты | Нашёл ошибку | Прислать материал | Добавить в избранное

    Все материалы представлены для ознакомления и принадлежат их авторам.