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

Процесс работы пользователей с интерактивными веб-сайтами может включать в себя шаг отправки им JavaScript-кода. Часто — слишком большого объёма такого кода. Если на сайте используется очень много JavaScript, это особенно сильно сказывается на мобильных пользователях. Например, вам случалось бывать на мобильных веб-страницах, которые, вроде бы, выглядят как уже готовые к работе, но не реагируют на щелчки по ссылкам или на попытки прокрутить страницу?
5pizilrb4dsozficzbjzb0-7xfm.jpeg

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

Общие положения


Взгляните на этот отчёт, демонстрирующий время, необходимое для обработки JavaScript-кода сайта CNN различными устройствами. Он построен на основе измерений, проведённых средствами проекта WebPageTest.org (вот таблица с исходными данными для этого отчёта, тут есть ещё данные по сайту Walmart).

8e65221fbbc2d3489f75fcd6f2b4e5c4.png


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

Как видно, телефон высшего класса (iPhone 8) справляется с задачей обработки JS-кода примерно за 4 секунды. Телефону среднего уровня (Moto G4) на решение той же задачи надо уже примерно 13 секунд. А бюджетному, хотя и современному устройству, такому, как Alcatel 1X, требуется около 36 секунд.

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

  • Для того чтобы веб-проекты работали быстро, нужно загружать лишь JavaScript-код, необходимый для текущей страницы. Использование технологий разделения кода (code splitting) позволяет организовать как можно более оперативную загрузку того, что пользователю точно понадобится, и применить методику ленивой загрузки (lazy load) для других фрагментов кода. Благодаря такому подходу страница получает шанс быстрее, чем в других случаях, загрузиться, и быстрее дойти до состояния, когда с ней можно будет взаимодействовать. Если вы используете системы, в которых, по умолчанию, применяется разделение кода, основанное на маршрутах, это меняет ситуацию в лучшую сторону.
  • Придерживайтесь ограничений, установленных в отношении параметров проекта, так называемого «бюджета производительности» (performance budget), и научитесь их соблюдать. Так, например, рассчитывайте на то, что размер минифицированного и сжатого JS-кода, необходимого для страниц, предназначенных для мобильных устройств, не должен превышать 170 Кб. При преобразовании таких материалов к обычному виду получается примерно 700 Кб кода. Подобные ограничения имеют огромную важность для успеха проекта, однако, только они одни не могут чудесным образом сделать медленный сайт быстрым. Здесь играют роль командная культура, структура и средства контроля за исполнением правил. Разработка проекта без бюджета способствует постепенному падению производительности и может привести к неприятным последствиям.
  • Научитесь проводить аудит JavaScript-бандлов (сборок) и сокращать их размер. Весьма вероятно, что клиентам приходится загружать полные версии библиотек, в то время как для работы проекта нужны лишь их части. Возможно, в проект включены полифиллы для браузеров, которые им не нужны, не исключено и дублирование кода.
  • Каждое взаимодействие пользователя с сайтом — это начало нового периода ожидания, по истечении которого с сайтом можно будет работать (это то, что называют «время до интерактивности», TTI, Time to Interactive). Оптимизации стоит рассматривать в этом контексте. Размер передаваемого кода весьма важен для медленных мобильных сетей, а время, необходимое на парсинг JavaScript-кода — для устройств со скромными вычислительными возможностями.
  • Если использование JavaScript на стороне клиента не приводит к улучшению пользовательского опыта — подумайте о том, нужно ли применять JS в данной ситуации. Возможно, в подобном случае быстрее было бы отрендерить HTML-код на сервере. Подумайте об ограничении использования клиентских веб-фреймворков, о применении их только для формирования страниц, которые совершенно не могут без этого обойтись. И рендеринг на сервере, и рендеринг на клиенте, при неправильном использовании этих технологий, превращаются в источник серьёзнейших проблем.


Современные веб-проекты и проблема чрезмерного использования JavaScript


Когда пользователь обращается к вашему сайту, то вы, вероятно, отправляете ему целую кучу файлов, многие из которых являются скриптами. С точки зрения веб-браузера это выглядит примерно так.

4c6152d3da036a4051873df5d22b9af5.gif


Примерно так чувствует себя браузер, который заваливают файлами

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

c91257c9d3dedf96b242c6fb4e1748f8.jpg


JavaScript — самая тяжёлая часть сайта

По данным июльского отчёта HTTP Archive, посвящённого использованию JavaScript, средняя веб-страница в наши дни предусматривает использование примерно 350 Кб минифицированного и сжатого JavaScript-кода. Этот код распаковывается в нечто вроде скрипта размером 1 Мб, который нужно обработать браузеру. Для того чтобы мобильный пользователь смог взаимодействовать с такой страницей, ему придётся ждать более 14 секунд.

2069be882fdb87d6c05781f32b4dc87f.jpg


Средняя страница, содержащая 350 Кб сжатого JS-кода, становится интерактивной на мобильном устройстве примерно через 15 секунд

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

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

Проанализируем состояние дел в области мобильных сетей, взглянув на данные OpenSignal. На следующем рисунке, слева, показана доступность 4G-сетей в мире (чем темнее цвет, которым закрашена территория страны — тем выше доступность), справа показаны скорости передачи данных (опять же — чем темнее — тем выше скорость). Страны, территория которых закрашена серым, в исследование не включены. Тут стоит отметить, что в сельской местности, даже в США, скорость мобильной передачи данных может быть на 20% медленнее, чем в городах.

dd5cab2b335865da3129d4aa7f16848e.png


Доступность 4G-сетей и скорость передачи данных

Выше мы говорили о том, что для загрузки и разбора 350 Кб минифицированного и сжатого JS-кода требуется определённое время. Однако если взглянуть на популярные сайты, окажется, что они шлют пользователям намного больше кода. Данные, представленные на рисунке ниже, взяты отсюда. Они представляют собой размеры распакованных JavaScript-бандлов различных известных веб-ресурсов, вроде Google Sheets, распакованный JS-код которого на настольных платформах занимает 5.8 Мб.

066369dddc8ca6a94e8618e9cf54778a.jpg


Размеры распакованных JavaScript-сборок для различных ресурсов

Как видите, и на настольных и на мобильных платформах браузерам, для работы с различными сайтами, иногда приходится обрабатывать по несколько мегабайт JS-кода. Главный вопрос здесь — можете ли вы позволить себе использовать такие большие объёмы JavaScript?

JavaScript — это не бесплатно


По словам Алекса Рассела, сайты, для работы которых требуются очень большие объёмы JavaScript, попросту недоступны для широких слоёв пользователей. По статистике пользователи не ждут (и не будут ждать) загрузки подобных ресурсов.

10284be1a4bb5a2df8c197f81f309841.jpg


Можете ли вы себе это позволить?

Если вам приходится отправлять пользователям слишком большие объёмы JS-кода — подумайте о применении технологии разделения кода для разбиения бандлов на небольшие части, или об уменьшении объёма кода с использованием алгоритма tree-shaking.

В состав JS-бандлов современных сайтов часто входит следующее:

  • Клиентский веб-фреймворк или библиотека пользовательского интерфейса.
  • Средство для управления состоянием приложения (например, Redux).
  • Полифиллы (часто для современных браузеров, которым они не нужны).
  • Полные версии библиотек, а не только те их части, которые реально используются (например — вся библиотека Lodash, библиотека Moment.js в варианте с поддержкой всех региональных стандартов).
  • Набор компонентов пользовательского интерфейса (кнопки, заголовки, боковые панели, и так далее).


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

Процесс загрузки веб-страницы похож на движущуюся в проекторе киноплёнку, на которой запечатлены три ключевых шага, отвечающих на следующие вопросы:

  • Это происходит? (Is it happening?).
  • Какая от этого польза? (Is it useful?).
  • Можно ли этим пользоваться? (Is it usable?).


Вот как можно представить эти шаги, которые, в свою очередь, можно разбить на более мелкие «кадры», если продолжать аналогию с киноплёнкой.

Загрузка страницы — это процесс. В последнее время фокус внимания веб-индустрии смещается к показателям, которые отражают ощущения пользователей от работы с веб-страницами. Вместо того, чтобы отдавать всё внимание событиям onload или domContentLoaded, теперь мы задаёмся вопросом о том, может ли пользователь по-настоящему работать со страницей. Если он щёлкнет что-нибудь на странице, последует ли за этим немедленная реакция?

541b449496d25038cb8282a337f7437c.png


Процесс загрузки веб-страницы

  • На шаге «Это происходит?» сайт может приступить к передаче каких-то данных браузеру. Здесь можно задаться вопросами о том, зафиксировано ли обращение браузера пользователя к серверу (например, по нажатию некоей ссылки), и о том, приступил ли сервер к формированию ответа.
  • На шаге «Какая от этого польза?» сайт выводит на экран некий текст или другое содержимое, которое позволяет пользователю, во-первых, узнать что-то полезное, а во-вторых, способно его заинтересовать.
  • На шаге «Можно ли этим пользоваться?» пользователь может начать полноценное взаимодействие с сайтом, которое может привести к неким событиям.


Интерактивные страницы и их проблемы


Выше мы упоминали такой показатель, как время до интерактивности (Time to interactive, TTI). Поговорим о нём подробнее. Ниже, на анимированном рисунке, который подготовил Кевин Шааф, можно видеть, как страница, не все материалы которой загружены и обработаны, заставляет пользователя думать, что он может выполнить некое действие, но, на самом деле, из-за того, что соответствующий JS код пока не до конца обработан, выполнить это действие нельзя.

ba2f9f4016b2992d3a6fcd6f42eb4d06.gif


Пользователей расстраивают страницы, которые слишком долго готовятся к работе

Для того чтобы страница была интерактивной, она должна иметь возможность быстро реагировать на воздействия пользователя. Маленькие объёмы JS-кода, приводящие страницы в действие, способствуют сокращению времени, необходимого для подготовки страниц к работе.

Если пользователь щёлкает по ссылке или прокручивает страницу, ему нужно видеть, что, в ответ на его действия, что-то происходит. Если страница не реагирует на воздействия пользователей, им это не нравится.

Вот отчёт, сформированный в тестовой среде средствами Lighthouse, содержащий набор показателей (здесь есть и Time to interactive), ориентированных на то, как страницу воспринимают пользователи.

43c41e5e2fc74e73b2b18e219464a02a.png


Отчёт Lighthouse, включающий в себя показатели, отражающие восприятие страницы пользователем

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

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

Загрузка слишком большого объёма JavaScript-кода средствами главного потока (например, такое происходит при использовании тега