Увеличиваем скорость загрузки web страниц

12 августа, 2008
javascript box

Недавно я наткнулся на одну очень интересную тему для WordPress - WP-Coda. Выглядит просто шикарно! Но дело не в этом.

Эта тема использует довольно много эффектов, реализованных с помощью JavaScript.

Мне стало интересно, во сколько эта красота обходится посетителям, и оказалось, что не так уж и дорого. Всего один js-файл размером 45кБ.

Дело в том, что автор упаковал семь исходных файлов в один и после этого сжал его упаковщиком вроде Packer JavaScript en PHP.

Но первый же эксперимент показал, что это не предел. Если упаковать этот файл в gzip архив, то его размер уменьшается до 21кБ. А большинство современных браузеров прекрасно работают с такими архивами.

При этом нет необходимости что-либо переделывать в самой теме.

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

После этого в файл .htaccess добавляем правила:

<IfModule mod_rewrite.c>
	RewriteEngine On
	AddEncoding gzip .gz
	RewriteCond %{HTTP:Accept-encoding} gzip
	RewriteCond %{HTTP_USER_AGENT} !Safari
	RewriteCond %{REQUEST_FILENAME}.gz -f
	RewriteRule ^(.*)$ $1.gz [QSA,L]
</IfModule>

Работают эти правила так.
1) включаем RewriteEngine;
2) указываем, что файлы с расширением .gz имеют MIME тип gzip;
3) начинаем проверки:
3.1) если браузер принимает gzip;
3.2) если это не Safari (у него вроде есть проблемы с gzip);
3.3) если существует файл с таким же именем, как и у запрошенного, но с расширением .gz;
4) если все проверки прошли успешно, то добавляем к имени файла расширение .gz и отправляем этот файл браузеру.

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

Посетитель разницы не заметит. Разве что немного увеличится время загрузки страницы.

В качестве примера, взгляните на скриншоты Firebug, сделанные для блога с темой WP-Coda.

Исходный вариант:

uncompressed javascript

После сжатия и установки правил в .htaccess:

compressed javascript

Кстати, заметьте, имя файла в обоих случаях одно и тоже. Изменяется только его размер. Т.е. браузер в обоих случаях считает, что получил файл, указанный в теге script (global.js), а сервер отправляет в первом случае global.js, а во втором - global.js.gz.

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

Вручную упаковывать файлы тоже не интересно, поэтому нужно автоматизировать процесс.

Для этих целей я написал небольшой php скрипт.

  1. //подключаем библиотеки
  2. require_once 'libs/jsmin-1.1.1.php';
  3.  
  4. /**
  5.  * Путь к папке со скриптами (отностильно этого скрипта)
  6.  */
  7. define('JS_DIR', "test_site/js/");
  8.  
  9. /**
  10.  * Имя упакованного файла (будет размещен в папке со скриптами)
  11.  */
  12. define('JS_OUTPUT_FILE', 'global.js');
  13.  
  14. //определяем папку в которой находится скрипт
  15. $scriptDir = substr($_SERVER['SCRIPT_FILENAME'], 0, strrpos($_SERVER['SCRIPT_FILENAME'], '/') + 1);
  16.  
  17. $resStr = "";
  18.  
  19. //открываем папку и получаем список файлов с расширением "js"
  20. if ($dh = opendir($scriptDir.JS_DIR)) {
  21.     while (false !== ($file = readdir($dh))) {
  22.         if ((substr($file, strrpos($file, '.') + 1) == "js") &amp;&amp;
  23.                 ($file != JS_OUTPUT_FILE)) {
  24.             $resStr .= "/*———".$file."———*/\n";
  25.             //сжимаем текущий файл
  26.             $resStr .= JSMin::minify(file_get_contents($scriptDir.JS_DIR.$file))."\n\n";
  27.         }
  28.     }
  29.     closedir($dh);
  30.     //сохраняем сжатые данные в файл
  31.     if ($fh = fopen($scriptDir.JS_DIR.JS_OUTPUT_FILE, 'w')) {
  32.         fwrite($fh, $resStr);
  33.         fclose($fh);
  34.     }
  35.     else {
  36.         echo "Ошибка: не могу открыть файл для записи: ".$scriptDir.JS_DIR.JS_OUTPUT_FILE;
  37.     }
  38.    
  39.     echo "Скрипты упакованы файл: ".JS_DIR.JS_OUTPUT_FILE."<br />";
  40.  
  41.     //архивируем данные (используем самую высокую степень сжатия)
  42.     $gzData = gzencode($resStr, 9);
  43.     //создаем архив
  44.     if ($fzip = fopen($scriptDir.JS_DIR.JS_OUTPUT_FILE.".gz", 'wb')) {
  45.         fwrite($fzip, $gzData);
  46.         fclose($fzip);
  47.     }
  48.     else {
  49.         echo "Ошибка: не могу открыть файл для записи: ".$scriptDir.JS_DIR.JS_OUTPUT_FILE.".gz";
  50.     }
  51.    
  52.     echo "Создан архив: ".JS_DIR.JS_OUTPUT_FILE.".gz";
  53. }
  54. else {
  55.     echo "Ошибка: не могу открыть папку со скриптами";
  56. }

Принцип работы следующий. Вы указываете папку с js файлами (JS_DIR) и имя файла в который будут упакованы все скрипты (JS_OUTPUT_FILE).

Скрипт читает содержимое всех файлов с расширением js из папки и сжимает его.

Примечание. Для сжатия используется PHP версия библиотеки JSMin. Она просто удаляет пробелы и комментарии из исходных файлов.

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

Следующим этапом php скрипт создает архив (с помощью функции gzencode), который получает имя JS_OUTPUT_FILE.gz.

Для тестирования я взял библиотеку jQuery и написал js-файл с небольшой функцией, которая создавала пару эффектов.

Т.е. в исходном варианте было 2 файла:
jquery-1.2.3.js – 96кБ
script.js – 1кБ

Сжатый вариант:
global.js – 53,1кБ

Архивный вариант:
global.js.gz – 16кБ

Как видите, разница довольно ощутимая.

Если есть желание поэкспериментировать, качайте архив с скриптом и библиотекой JSMin.

До встречи!

Понравилась статья? Подпишитесь на продолжение rss link !

]]>

Добавьте эту страницу в google.com bobrdobr.ru del.icio.us technorati.com linkstore.ru news2.ru rumarkz.ru memori.ru moemesto.ru

]]>

Опубликовано в JavaScript, PHP, Web разработка

]]>

Комментарии (10)

Вы можете отслеживать обсуждение записи с помощью RSS 2.0 rss link

Вы также можете оставить комментарий, или трекбек с Вашего сайта.

  1. zuborg 12.10.2008 в 16:19 (Ответить)

    Подход категорически правильный.
    Какой смысл при каждом http-запросе выполнять сжатие когда можно сделать это один раз.
    Кстати, этот метод и с html и css отлично работает, не только js )

    А чтоб не возиться с скриптами которые будут сравнивать время обновления, я бы рекомендовал сделать скрипт который будет генерить Makefile, и переложить работу по сравнению времен src и dst файлов на программу make. То есть просто в Makefile указать например что file.html.gz зависит от file.html и для создания file.html.gz надо запустить команду gzip -k file.html. Теперь после изменений достаточно будет просто набрать make чтоб обновить все *.gz файлы :)

    А оценить эффективность сжатия можно например онлайн-тулзой для оценки скорости загрузки сайтов - http://Site-Perf.com/

    1. Владимир 12.10.2008 в 18:20 (Ответить)

      ИМХО вместо make удобнее использовать Ant или Phing (если проект на PHP)

  2. Дима 10.11.2008 в 01:40 (Ответить)

    Способ хороший.
    Столкнулся со следующей проблемой.
    На локалке упаковал js-файлы в архив, прописал строки в .htaccess. Всё ок, радости не было предела :)
    Когда всё это добро вылил в инет, браузер не хотел воспринимать упакованные файлы… :( При прямом запросе js-файла предлагалось сохранить его на диск либо открыть WinRar'ом.
    Проблему решил прописыванием типа в .htaccess
    AddType application/x-javascript gz
    Может пригодится кому.

    1. Владимир 10.11.2008 в 20:10 (Ответить)

      Интересно, честно говоря не сталкивался с такой проблемой, спасибо.

  3. Владимир 16.11.2008 в 14:05 (Ответить)

    Решение очень понравилось. Но у меня возникли сложности с реализацией - что-то не так делаю с кодировками.
    Сжатый файл читается, но оказывается в неправильной кодировке. пробовал сохранять исходник в UTF-8, Unicode, ANSI - результат один. Это происходит как на localhost, так и на хостинге.
    Как с этим бороться?

    1. Владимир 16.11.2008 в 14:48 (Ответить)

      Возможно, дело не в кодировке, а в сжатии (неправильно распаковывается браузером).
      Какой архиватор используете? Очень советую 7-zip. С ним проблем не было (формат архива GZip).

      1. Владимир 17.11.2008 в 01:59 (Ответить)

        Как раз его и использую. И именно этот формат.

        1. Владимир 17.11.2008 в 19:04 (Ответить)

          Тогда давайте сделаем так. Я вам почтой отправил два скрипта. Со сжатием и без. Посмотрите как они у вас будут работать.

      2. Владимир 18.11.2008 в 19:26 (Ответить)

        Я нашел причину. Проблема в степени сжатия. Сжимал "ультра" - не работает, "максимальный" - работает.
        Ура! Спасибо!

        1. Владимир 19.11.2008 в 22:35 (Ответить)

          Да, браузер все-таки не архиватор… Разработчикам есть над чем поработать.

Оставить комментарий

Введите ваш комментарий

* - обязательные для заполнения поля

Quicktags:

]]>