Как оптимизировать загрузку js для многостраничных сайтов?

Исходные условия проблемы примерно таковы - есть многостраничный сайт, скажем так "портального" типа, но не очень большой. Бэкэнд традиционно написан на php. На фронтэнде используем jquery со всякими сторонними и своими плагинами для улучшения пользовательского интерфейса - всякие там лайтбоксы, календари, всплывающие подсказки и прочий довольно стандартный зоопарк.

Не так давно нами было решено внедрить модульный подход? асинхронную загрузку с использованием require.js и разделение бэкэнда и фронтэнда. Внедрение прошло удачно, но встал вопрос как теперь оптимизировать загрузку яваскриптов?
Самое популярное решение для require.js, которое предлагается везде, это используя r.js склеить все в один файл и подключать его на продакшене. Но, простите, друзья, для чего мы тогда внедряем всю эту модульность? Только ради удобства в разработке?

У нас в общей сумме на сайте используется около 300-400 кб разного яваскрипта, причем это использование идет совершенно неравномерно по разделам. И мне кажется, что запаковать это все в один файл и отдавать каждому посетителю не совсем правильно. Дело в том, что наш среднестатистический пользователь может никогда не дойдет до страницы или раздела сайта, где мы используем datepicker или загрузку фото, или еще какие-то специфические скрипты. Так зачем мы будем его нагружать этими подарками при первой встрече, заставлять его качать все 400 кб скриптов, а потом заставлять его браузер проводить синтаксический анализ всего этого кода.

Сейчас у нас используется какое-то промежуточное решение, которым мы по прежнему не очень довольны. При первой встрече мы отдаем пользователю минимальный набор необходимых скриптов (100-150 кб), а остальное подтягиваем в виде requirejs модулей. В итоге получаем, что при большом количестве интерактивных элементов на некоторых страницах, в дополнение к базовому набору скриптов у нас запрашивается и качается еще 5-7 javascript файлов. С точки зрения оптимизации, кажется, это тоже не очень красивое решение.

Наверное, не мы первые сталкиваемся с таким вопросом. Сайт у нас не уникальный и проблема тоже.
Что же выгоднее делать с точки зрения правильной клиентской оптимизации:
1. Паковать все скрипты в один файл, отдавать его сразу и не заботиться, что большая часть из этих скриптов не будет востребована многими посетителями сайта?
2. Пытаться как-то поделить скрипты. Отдавать только то, что нужно посетителю на конкретной странице сайта?

Если идти вторым путем, то что делать с оптимизацией? Как быть если страница требует загрузки десятка мелких js модулей?
  • Вопрос задан
  • 5723 просмотра
Пригласить эксперта
Ответы на вопрос 7
Fesor
@Fesor
Full-stack developer (Symfony, Angular)
минифицировать все и отдавать с gzip с правильными настройками HTTP кэша. Один раз загрузили и больше не дергаем на все страницы.
Ответ написан
@PiloTeZ
...
Сделайте подключение javascript файлов в самом javascript.
Например:
- фронтенд получил jquery и jquery ui, и записал их в список полученных скриптов
- далее сервер опять предлагает получить jquery и JQueryCookie, javascript проверяет и в итоге запрашивает только JQueryCookie
В общем записывайте все скрипты, которые получили и при следующих загрузках проверяйте, нужны ли они
Ответ написан
Petroveg
@Petroveg
Миром правят маленькие с#@&ки
Мне кажется, что вопрос единовременной загрузки скриптов вовсе не в весе. Что такое нынче 300-400 кб? Так, ерунда... (up: для мобильных устройств может оказаться и не ерундой, что не меняет подхода в целом)

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

Опять же, моё мнение, на некоторые тяжёлые скрипты, способные вызвать тормоза в построении страницы, лучше потратить запрос, чем заставлять пользователя ждать наступления реакции документа. И грузить, по возможности, асинхронно.
Ответ написан
@dmtr81 Автор вопроса
Благодаря обсуждению в комментариях и еще некоторым изысканиям я пришел к следующему. Во-первых, вопрос оптимизации нужно разделить на 2 пункта и каждый из них обсудить отдельно.
1. Загрузка скриптов на устройство пользователя. Здесь однозначный вариант одобренный всеми - объединить все скрипты в один файл, минифицировать его, сжать и положить в кэш пользователю при первом визите.
2. Выполнение скриптов на устройстве пользователя. Здесь сложнее. Во-первых, оно происходит на каждое открытие страницы независимо от того взят скрипт из кэша или нет. Если вы не проводили никакой оптимизации, а просто объединили все свои скрипты в один файл, то сразу же после загрузки (взятия из кэша) браузер пользователя начнет их анализ и выполнение. Это занимает время, а на это время браузер пользователя "замирает". В зависимости от мощности устройства (десктоп или телефон) и размера вашего объединенного яваскрипта это выполнение можно занимать от долей секунды до нескольких секунд. Но даже замирание в 0.2-0.3 секунды вполне заметно для пользователя.
Полезные ссылки по этой теме:
calendar.perfplanet.com/2011/lazy-evaluation-of-co...
habrahabr.ru/post/145269

Остается вопрос, как совместить первое и второе, т.е. отдать пользователю весь js в одном большом файле, но заставить браузер выполнять только нужный на данной странице код, а ненужный не выполнять. Решение этому есть! Называется отложенное (ленивое) выполнение яваскрипта, по английски, delay (lazy) javascript evaluation. Т.е. если вы весь код объединяете в один файл и у вас этого кода много, позаботьтесь о том, чтобы выполнялся только тот код, который нужен на текущей странице.

В интернете достаточно решений по этому поводу, но т.к. мы используем require.js, я смотрел, как это решено в данной библиотеке. Начиная со 2 версии require.js умеет откладывать выполнение яваскрипта и делает это автоматически для всех модулей объявленных через define. Важно знать, что для скриптов написанных не в формате AMD и подключенных через shim (например плагинов jquery) отложенное выполнение не работает и они выполняются сразу же при загрузке. К сожалению, у нас таких плагинов довольно много и придется что-то делать, например, оборачивать их в модули requirejs. Но, кажется, это не очень большая проблема.

В итоге короткий ответ на вопрос такой: пакуем все скрипты в один файл, но обязательно заботимся об отложенном выполнении скриптов, чтобы не нагружать браузер лишней работой, а пользователя задержками на выполнение ненужного яваскрипта.
Ответ написан
Комментировать
IonDen
@IonDen
JavaScript developer. IonDen.com
Если вас так беспокоит вопрос, что скрипты все время дергаются с сервера, то положите их в клиентское хранилище, воспользовавшись например таким инструментом.

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

Есть еще и другое мнение, рассматривать сайт как приложение (ну вот например как на смартфонах). В чем прелесть такого подхода? А в том что при запуске приложения, вся оболочка этого приложения загружается разом. А потом, загружаются только голые данные, что дает небывалую скорость отклика и отзывчивость. На обычных сайтах такого не встретишь. В такой ситуации вам не только скрипты и стили, но еще и всю графику сайта придется как то предзагрузить и хранить на клиенте.
Ответ написан
Первый вариант самый правильный!
Ответ написан
Сжать через r.js единственно верное решение, даже скрипт весом в 1mb это мелочь по сравнению с общим весом средне–статистической страницы с учетом картинок. А учитывая что скрипт загружается один раз и затем кешируется браузером, то тут и совсем нет повода переживать из за лишнего веса.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы