Цена JavaScript

По мере того как наши сайты всё сильнее зависят от JavaScript, приходится расплачиваться за то, что мы отправляем пользователям. Иногда цена не видна с первого взгляда. В этой статье я объясню, почему полезно проявить немного дисциплины, если вы хотите ускорить загрузку и производительность на мобильных устройствах.

Сеть

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

Это может стать проблемой даже в странах первого мира, поскольку эффективный тип сетевого соединения у пользователя необязательно 3G, 4G или WiFi. Вы можете сидеть в кафе с WiFi, но быть подключённым к хотспоту через сотовую связь со скоростью 2G.

Расходы на сетевую передачу JavaScript можно сократить следующими способами:

  • Передавать только код, который нужен пользователю;
  • Минификация;
  • Максимальное сжатие;
  • Удалить неиспользуемый код. Его можно выявить инструментом покрытия кодом в DevTools;
  • Кэширование для сокращения сетевого трафика. Определите оптимальное время жизни скриптов (max-age) и обеспечьте токены валидации (ETag), чтобы не передавать неизменившиеся байты.

Парсинг/компиляция

После скачивания кода JavaScript одной из главнейших затрат становится время разбора/компиляции этого кода в JS-движке. В Chrome DevTools парсинг и компиляция — часть жёлтого времени Scripting на панели Performance.

На вкладках Bottom-Up и Call Tree можно посмотреть точное время парсинга и компиляции:

Большой расход времени на разбор и компиляцию кода может сильно увеличить задержку на взаимодействие пользователя с сайтом. Чем больше кода JavaScript вы отправляете, тем дольше будет продолжаться этап разбора и компиляции, прежде чем сайт начнёт откликаться на действия пользователя.

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

Когда мы говорим о медленном разборе и компиляции, важен контекст — здесь мы говорим о средних мобильных телефонах. У обычных пользователей могут быть телефоны с медленными CPU и GPU, без кэша L2/L3 и даже с ограниченным объёмом памяти.

Возможности сети и возможности устройства не всегда совпадают. У пользователя на отличном оптоволоконном канале необязательно отличный CPU для разбора и оценки JavaScript, который приходит на его устройство. Верно и обратное… ужасное сетевое соединение, но исключительно быстрый процессор.

Современный iPhone 8 тратит примерно 4 с на парсинг/компиляцию скриптов CNN, по сравнению с ~13 с на среднем телефоне (Moto G4). Это может значительно повлиять на то, сколько времени пройдёт, прежде чем пользователь получит возможность взаимодействовать с сайтом (Время парсинга на чипе Apple A11 Bionic по сравнению со Snapdragon 617 в обычном смартфоне Android).

HTTP Archive (топ около 500 тыс. сайтов) показывает использование JavaScript на мобильных сайтах. И мы видим, что 50% сайтам требуется больше 14 секунд, прежде чем они становятся интерактивными. Эти сайты тратят до четырёх секунд только на разбор и компиляцию JS.

Если учесть ещё время, нужное для загрузки и обработки JS и других ресурсов, то ничего удивительного, что пользователи покидают страницу, не дождавшись её «разморозки». Здесь определённо есть пространство для улучшения. Если удалить со страниц некритичные JavaScript, то вы сократите время загрузки, CPU-интенсивные парсинг/компиляцию и потенциальный перерасход памяти. Это также поможет вашим страницам быстрее входить в интерактивный режим.

Время выполнения

Свою цену имеют не только разбор и компиляция. Выполнение JavaScript (исполнение кода после парсинга/компиляции) — одна из операций, которая выполняется в основном потоке. Большое время выполнения тоже влияет на то, как скоро пользователь сможет взаимодействовать с вашим сайтом.

Если цель сократить время парсинга/компиляции JavaScript и передачи по сети, есть некоторые полезные техники, такие как разделение на части по проходам (route-based chunking) и PRPL.

PRPL Pattern:

  • Push critical resources for the initial URL route.
  • Render initial route.
  • Pre-cache remaining routes.
  • Lazy-load and create remaining routes on demand.

PRPL — это техника оптимизации интерактивности путём агрессивного разделения кода на фрагменты и кэширования.