CSS практик

Оптимизация JavaScript

Posted by: fxix on: Сентябрь 10, 2008

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

  1. JSMin. Наиболее широко распространенный минимизатор, основывается на простых правилах, портирован на множество языков, в том числе, и на сам JavaScript.
  2. JavaScript::Minifier. Отдельный перловый модуль, по степени сжатия очень близок к JSMin, однако генерирует отличный от первого синтаксис.
  3. Dojo ShrinkSafe aka Rhino. Первоначально разрабатывался как Rhino, затем был включен в состав Dojo. Запускается как jar-модуль.
  4. Dean Edwards Packer. Достаточно широко известный инструмент от не менее известного Dean Edwards. Портирован на некоторые языки, в том числе, на PHP4/5.
  5. YUI Compressor. В представлении также не нуждается, именно на его основе проведена оптимизации сайтов Yahoo. Для анализа использовалась версия 2.2.5. Запускается как jar-модуль.

Файлы сжимались всеми представленными инструментами, затем архивировались. Заметен явный выигрыш Packer’а без архивирования. Для уточнения картины при архивировании минимизированного файла я отдельно выделил их преимущество (если оно имеется) относительно обычного архивирования.  Тут уже хорошо видно, что 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). Хочется отметить, что при минимизации JS-файлов нужно следить за тем, чтобы функционал не уменьшился вследствие этой самой минимизации. Для проверки JS-файлов на работоспособность и общую адекватность существует проект JSLint, который, я так понимаю, сравнивает исходный файл с набором спецификаций по синтаксису и выдает сообщения об обнаруженных ошибках. Однако у общественности нет однозначного отношения к данному проекту, да и тема тестирования JS-приложений требует отдельного рассмотрения.

2.  Делать загрузку JavaScript «отложенной».

Одной из наиболее частых проблем из рассматриваемого комлекса является прямое исполнение JavaScript по ходу загрузки страницы, хотя этого можно и избежать. Если код скрипта не изменяет содержимое страницы (DOM) при загрузке, то выполнение этого кода может быть отложено до полной загрузки страницы. Таки образом, сначала появится содержание страницы, а потом уже будут выполняться все отложенные скрипты. К несчастью, это поддерживается не всеми браузерами. Подробнее про атрибут defer у тега <script>.

Уменьшайте объем кода, который должен выполниться при полной загрузке страницы (при событии window.onload) Все, что исполняется после загрузки страницы, увеличивает время этой загрузки. Чем меньше кода будет выполнено, тем лучше. Другим важным моментом является отсечение зависимостей для загрузки конкретной страницы (когда загрузка зависит от ряда внешних загрузок или вызовов). Это большая проблема, т.к. может повлечь «подвисший» вызов скрипта. В любом случае, JavaScript код, который исполняется несколько секунд, является узким местом (bottleneck) при загрузке страницы. Используя разбиение выполнения кода на отдельные независимые части при помощи задержек (timeouts) можно частично решить эту проблему, хотя это и довольно дорогой («болезненный») путь. Также в этом случае может помочь использование «ненавязчивого» (unobtrustive) JavaScript.

jQuery загружается достаточно быстро относительно других библиотек (200–400мс — существенный выигрыш в скорости).