[Перевод] Цена JavaScript в 2019 году

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

7xg6g_poas_6_4qwu5u4clgjxrs.jpeg

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

Общие практические рекомендации по оптимизации сайтов


Что вышесказанное означает для веб-разработчиков? Дело тут в том, что затраты ресурсов на парсинг (разбор, синтаксический анализ) и компиляцию скриптов уже не так серьёзны, как раньше. Поэтому при анализе и оптимизации JavaScript-бандлов разработчикам стоит прислушаться к следующим трём рекомендациям:

  1. Стремитесь снизить время, необходимое на загрузку скриптов.
    • Постарайтесь, чтобы ваши JS-бандлы имели бы небольшой размер. Особенно это важно для сайтов, рассчитанных на мобильные устройства. Использование маленьких бандлов улучшает время загрузки кода, снижает уровень использования памяти, уменьшает нагрузку на процессор.
    • Старайтесь, чтобы весь код проекта не был бы представлен в виде одного большого бандла. Если размер бандла превышает примерно 50–100 Кб — разделите его на отдельные фрагменты небольшого размера. Благодаря HTTP/2-мультиплексированию одновременно может выполняться отправка нескольких запросов к серверу и обработка нескольких ответов. Это снижает нагрузку на систему, связанную с необходимостью выполнения дополнительных запросов на загрузку данных.
    • Если вы работаете над мобильным проектом — постарайтесь, чтобы код был бы как можно меньшего размера. Эта рекомендация связана с невысокими скоростями передачи данных по мобильным сетям. Кроме того, стремитесь к экономному использованию памяти.
  2. Стремитесь снизить время, необходимое на выполнение скриптов.
    • Избегайте использования длительных задач, которые способны на долгое время нагружать главный поток и увеличивать время, необходимое на то, чтобы страницы оказывались бы в состоянии, в котором с ними могут взаимодействовать пользователи. В текущих условиях выполнение скриптов, происходящее после того, как они оказываются загруженными, вносит основной вклад в «цену JavaScript».
  3. Не встраивайте большие фрагменты кода в страницы.
    • Здесь стоит придерживаться следующего правила: если размер скрипта превышает 1 Кб — постарайтесь не встраивать его в код страницы. Одной из причин этой рекомендации является тот факт, что 1 Кб — это тот предел, после которого в Chrome начинает работать кэширование кода внешних скриптов. Кроме того, учитывайте то, что разбор и компиляция встроенных скриптов всё ещё выполняются в главном потоке.


Почему так важно время загрузки и выполнения скриптов?


Почему в современных условиях важно оптимизировать время загрузки и выполнения скриптов? Время загрузки скриптов чрезвычайно важно в ситуациях, когда с сайтами работают через медленные сети. Несмотря на то, что в мире всё сильнее распространяются сети 4G (и даже 5G), свойство NetworkInformation.effectiveType во многих случаях использования мобильных соединений с Интернетом демонстрирует показатели, находящиеся на уровне 3G-сетей или даже на более низких уровнях.

Время, необходимое на выполнение JS-кода, важно для мобильных устройств с медленными процессорами. Из-за того, что в мобильных устройствах используются различные CPU и GPU, из-за того, что при перегреве устройств, ради их защиты, производительность их компонентов снижается, можно наблюдать серьёзный разрыв между производительностью дорогих и дешёвых телефонов и планшетов. Это сильно влияет на производительность JavaScript-кода, так как возможности по выполнению неким устройством такого кода ограничены возможностями процессора этого устройства.

На самом деле, если проанализировать общее время, тратящееся на загрузку и подготовку к работе страницы в браузере наподобие Chrome, то около 30% этого времени может быть потрачено на выполнение JS-кода. Ниже показан анализ загрузки весьма типичной по составу веб-страницы (reddit.com) на высокопроизводительном настольном компьютере.

31d8f6af06d7158ecc9bd17710d216bb.png


В процессе загрузки страницы около 10–30% времени тратится на выполнение кода средствами V8

Если говорить о мобильных устройствах, то на среднем телефоне (Moto G4) на выполнение JS-кода reddit.com уходит в 3–4 раза больше времени, чем на устройстве высокого уровня (Pixel 3). На слабом устройстве (Alcatel 1X стоимостью менее $100) на решение той же задачи требуется, как минимум, в 6 раз больше времени, чем на чём-то вроде Pixel 3.

71a4f03a9f7d673740c6917f30cee360.png


Время, необходимое на обработку JS-кода на мобильных устройствах разных классов

Обратите внимание на то, что мобильная и настольная версии reddit.com различаются. Поэтому здесь нельзя сравнивать результаты мобильных устройств и, скажем, MacBook Pro.

Когда вы пытаетесь оптимизировать время выполнения JavaScript-кода — обращайте внимание на длительные задачи, которые могут надолго захватывать UI-поток. Эти задачи могут препятствовать выполнению других, чрезвычайно важных задач, даже тогда, когда внешне страница выглядит полностью готовой к работе. Длительные задачи стоит разбивать на более мелкие задачи. Деля код на части и управляя порядком загрузки этих частей можно добиться того, что страницы быстрее будут приходить в интерактивное состояние. Это, можно надеяться, приведёт к тому, что у пользователей будет меньше неудобств во взаимодействии со страницами.

002eef32b869be9ae677bc41b41c86c2.png


Длительные задачи захватывают главный поток. Их стоит разбивать на части

Как улучшения V8 влияют на ускорение разбора и компиляции скриптов?


Скорость синтаксического анализа исходного JS-кода в V8, со времён Chrome 60, повысилась в 2 раза. В то же время, парсинг и компиляция теперь вносят меньший вклад в «цену JavaScript». Это так благодаря другим работам по оптимизации Chrome, ведущим к параллелизации выполнения этих задач.

В V8 объём работ по разбору и компиляции кода, производимых в главном потоке, снижен в среднем на 40%. Например, для Facebook улучшение этого показателя составило 46%, для Pinterest — 62%. Наиболее высокий результат, составляющий 81%, получен для YouTube. Такие результаты возможны благодаря тому, что парсинг и компиляция вынесены в отдельный поток. И это — вдобавок к уже существующим улучшениям, касающимся потокового решения тех же задач за пределами главного потока.

4a741e24c05a9149d98ee568be74b564.png


Время парсинга JS в различных версиях Chrome

Ещё можно визуализировать то, как оптимизации V8, производимые в различных версиях Chrome, воздействуют на процессорное время, необходимое для обработки кода. За то же время, которое Chrome 61 нужно было для парсинга JS-кода Facebook, Chrome 75 теперь может разобрать JS-код Facebook и, вдобавок, 6 раз разобрать код Twitter.

c6b0000e0b2bb98087ff12f8a9eb0d97.png


За то время, которое Chrome 61 было нужно для обработки JS-кода Facebook, Chrome 75 может обработать и код Facebook, и шестикратный объём кода Twitter

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

  • V8 может выполнять парсинг и компиляцию JS-кода не блокируя главный поток.
  • Потоковая обработка скрипта начинается с того момента, когда универсальный HTML-парсер встречает тег