Сравнение производительности JS-фреймворков на RealWorld Demo

Во-первых, сразу вам сообщу, что в тестах производительности я полный неудачник. Поэтому я начал свой путь с написания реактивной UI-библиотеки на JavaScript, чтобы хоть что-то доказать. Меня это настолько увлекло, что я решил не останавливаться до тех пор, пока не добьюсь ее подтвержденного превосходства над аналогами в сфере виртуальной DOM в первую очередь по показателям производительности. Началось все это 5 лет назад, 4 из которых ушли на достижение поставленной цели.

Итак, я говорю о SolidJS, современной полнофункциональной реактивной JS-библиотеке. Она включает в себя все JSX-компоненты, API в стиле хуков, контекст, порталы, фрагменты, задержку, поддержку web-компонентов, SSR, остальное можете перечислить сами. При этом она, по всей видимости, является наиболее производительной библиотекой в своем семействе (см. ниже), но сегодня мы будем говорить не об этом. Вместо углубленного рассмотрения производительности отрисовки мы более целостно рассмотрим производительность в приложениях. 

Результаты бенчмарка JS-фреймворков в Chrome 80 (февраль 2020)

RealWorld Demo

gothinkster/realworld
While most «todo» demos provide an excellent cursory glance at a framework’s capabilities, they typically don’t convey…github.com

RealWorld Demo  —  это крупный открытый проект, поддерживаемый сообществом. Он демонстрирует все клиентские и серверные web-фреймворки на примере построения с их помощью образца приложения, что гораздо обстоятельней, чем типичные игрушечные демо TodoMVS или пустые сценарии, которые встречаются в бенчмарках. Как и используемый для теста Conduit, своеобразный клон Medium, ваше приложение должно обрабатывать реальные задачи вроде аутентификации, маршрутизации и асинхронной загрузки данных. В RealWorld Demo есть стандартизированная спецификация, что делает его еще более привлекательным местом для покупки очередной библиотеки или фреймворка.

Но мы, будучи одержимы производительностью, на этом не останавливаемся. Вместо отрисовки 10 000 вращающихся кубов или строк в таблице мы рассмотрим оптимизацию загрузки, размер кода, а также оценим удобство для пользователей и разработчиков. При столь амбициозном настрое задача кажется вполне себе простой: создать самую маленькую и самую быструю реализацию, которую все захотят использовать сразу, как только увидят. В случае с Solid это означало необходимость акцентирования ее достоинств и тестирование пределов возможностей одностраничного приложения, отображаемого исключительно на клиентской стороне. В ходе процесса мы будем сопоставлять Solid с другими библиотеками, включая Svelte, лидера этого демо, использующего SSR (server side rendering). Таким образом я проверял гипотезу.

Я заметил, что разрыв в скорости отрисовки между более скоростными и менее скоростными библиотеками особо выражен на маломощных устройствах. Если библиотека вроде Solid уже на несколько сотен миллисекунд быстрее отрисовывает большое количество узлов, то в каких точках первые важные появления контента, обусловленные использованием SSR, не оказывают значительного влияния?

Тест

Сразу скажу, что используемый метод тестирования вряд ли можно считать убедительным. Я просто прогнал каждую реализацию 10 раз и усреднил 3 наилучших результата. За основу я взял сравнение, которое проводится для них ежегодно. Вот, к примеру, результаты 2019 года:

A RealWorld Comparison of Front-End Frameworks with Benchmarks (2019 update)
by Jacek Schae A RealWorld Comparison of Front-End Frameworks with Benchmarks (2019 update)Also available in: Turkish …www.freecodecamp.org

В этом тесте сравниваются 3 метрики: производительность, размер и LOC (количество строк кода). Я же добавил несколько других метрик из собственных тестов, чтобы дать более развернутое представление, но суть сравнения осталась прежней. Производительность проверялась с помощью аудитов Chrome Lighthouse. Размер  —  это общий размер JS-кода в Кб, отправляемый для отрисовки начальной страницы. И наконец, LOC измеряется при помощи cloc, который складывает общее количество строк JS, CSS и HTML, хранящихся в каталоге src (т.е. код библиотеки не включается).

Это однозначно не официальное сравнение. Solid на данный момент ожидает слияния, поэтому я хотел воспользоваться возможностью проверить, как он себя покажет. Я выбрал лидеров по данным сравнения 2019 года и добавил популярные библиотеки React, Angular, а также Vue. С образцом приложения Solid вы можете ознакомиться здесь:Conduit
Edit descriptionryansolid.github.io

Производительность

Показатель производительности в Lighthouse

Если учесть разброс сравниваемых библиотек, то этот тест дал наиболее близкие результаты, чем другие. Аудит Lighthouse для всех библиотек дает показатель меньше 100, отталкиваясь от таких начальных метрик загрузки, как время до первого байта (TTFB), первая полноценная отрисовка (FCP), время до активации интерактивности (TTI) и максимальная задержка ввода (MID). Все библиотеки выполняются в условиях слабого CPU и пропуска сетевых пакетов, чтобы симулировать их работу на низкобюджетных устройствах в условиях слабого интернет-соединения. Половина участников теста показывает практически идеальные результаты. Популярные же библиотеки несколько уступают в скорости. Лидирует среди них Vue, а React Redux плетется в хвосте. 

Никаких существенных различий мы не обнаружили, поэтому давайте взглянем на один из наиболее завышенных показателей, а именно время до активации интерактивности (TTI). Он показывает момент, когда страница становится доступной для обращения пользователя. 

Показатели времени до активации интерактивности в сек (чем меньше, тем лучше)

И снова 5 ведущих библиотек оказываются рядом, особенно Svelte и Solid. Здесь мы видим реальное влияние снижения производительности на популярные библиотеки, среди которых Angular и React Redux для активации интерактивности требуется более 5.5 сек.

В этот момент я решил просмотреть еще несколько репозиториев в поиске более высоких результатов производительности в RealWorld. Перепробовав с десяток, я нашел только один: Microsoft Blazor. Blazor  —  это библиотека Web Assembly, позволяющая писать приложения на C# и выполнять их в браузере. Ее показатель был 99. Впечатляет. 

…что ж, так бы оно и было, если бы в итоге она не оказалось самой медленной библиотекой, какую я только встречал. Настолько медленной, что Chrome решил, что загрузка завершилась, хотя сама библиотека еще находилась на экране загрузки. В итоге высокий показатель скорости она получила благодаря быстрой отрисовке именно экрана загрузки. Я же взглянул на график производительности Chrome, который отражал совсем другую историю. Увидев, насколько отличались показатели, я решил посмотреть, как эти библиотеки справятся с трассировкой стека.

Трассировка в Chrome Inspector в мс (чем меньше, тем лучше)

Теперь общее время загрузки ресурсов, отображенное на графике, не является четким показателем скорости загрузки страницы, поскольку происходит загрузка и выполнение JavaScript, а также отрисовка узлов DOM. В отличие от TTI эти числа составляют примерно 1 секунду. Единственный интересный момент здесь  —  это то, что библиотеки с разделением кода, за исключением Solid (Svelte, AppRun), оказались медленнее пропорционально их размеру. В то же время бандлы среднего размера, например Elm и HyperApp, загрузились гораздо быстрее.

Существенное отличие здесь в том, что приложение Solid разделено всего на 3 части, а Svelte и AppRun примерно на 8. Возможно, что ограничение браузера по количеству параллельных подключений не позволило быстро выполнить одновременную загрузку более раздробленного кода. Solid также использует реализацию Render as You Fetch, которая содержит вызовы API, совершаемые перед загрузкой кода маршрута, что, вероятно, тоже способствует сокращению времени загрузки.

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

Размер

Начальный размер JS-страницы в Кб (чем меньше, тем лучше)

Раньше этот тест измеряли иначе, анализируя только начальный фрагмент кода. Я же думаю, что важно рассматривать весь JS, необходимый для загрузки первой страницы. Solid опередил предыдущего лидера этой таблицы Svelte, так как загрузить пришлось всего 12.1 Кб против 14.8 Кб Svelte. Это первый тест, в котором Solid оказался меньше. Как правило, меньшим оказывается именно Svelte, причем примерно на 50%. Предыдущее сравнение показало, что, когда весь JS для всех страниц загружен, размер кода Svelte на деле получался больше, чем размер кода Elm. Это говорит о том, что Svelte, вероятно, не масштабируется по размеру и по компонентам. Большинство бенчмарков склоняют вас выполнять всю работу в одном компоненте. Поэтому размер AppRun для всего приложения составил всего 18Кб, сделав его победителем среди библиотек с неразделенным кодом. 

Дополнение от 24.03.2020: с момента публикации этой статьи Solid был уменьшен до 11.1Кб.

Заключение: Все рассмотренные показатели отражают логичное развитие вещей. Когда-то на фоне появления React Redux огромным показался Angular, а теперь есть такие библиотеки, как Solid, которые почти что в 20 раз меньше. 

Количество строк кода

Количество строк кода (чем меньше, тем лучше)

В этом тесте Svelte определенно сохраняет свою репутацию. Может несколько удивить, что все следующие за ним 4 библиотеки используют JSX, за ними идут Vue и Angular со строчными шаблонами, потом еще одна JSX-библиотека и в завершении Elm. Elm выделяется огромным числом строк, которых в нем чуть ли не в два раза больше, чем в остальных библиотеках. Тем не менее, если вкратце взглянуть на исходный код, становится понятно, что причина кроется в вертикальном стиле его написания. В Solid тоже многовато строк, если сравнивать с его размером. Я решил отобразить полученную информацию графически, но не уверен, что это имеет какое-либо значение. 

Заключение: до сих пор неясно, имеет ли этот показатель LOC какое-либо значение.

Размер/LOC (Кб/LOC*1000)

Можно ли считать это демо “Real World”?

Думаю, в некотором смысле да. Solid следует в этом демо традиционной политике минимализма. В нем не используются сторонние библиотеки AJAX, маршрутизатор прописан в нескольких десятках строк, отсутствует система управления глобальным состоянием и библиотека проверки форм. 

И все же продемонстрировать здесь можно многое. Рассматриваемое приложение эффективно использует в магазине примитивы Solid наряду с Context API, создавая достаточно привлекательный для сторонней библиотеки облик. Кроме того, оно также полноценно использует Suspense с Lazy Components и Data Fetching. В частности, можно выделить технику Render as You Fetch, в которой получение данных инициализируется до разрешения маршрута в основной части кода, и данные с кодом получаются одновременно. Если код загружается раньше, то он начинает выполнять отрисовку фоном, завершая Suspense только при поступлении данных. 

ryansolid/solid-realworld
Solid.js codebase containing real world examples (CRUD, auth, advanced patterns, etc) that adheres to the RealWorld…github.com

Добавьте описание

ryansolid/solid
A declarative, efficient, and flexible JavaScript library for building user interfaces. — ryansolid/solidgithub.com

Добавьте описание

Читайте также:

Читайте нас в Telegram, VK и Яндекс.Дзен


Перевод статьи Ryan CarniatoA Solid RealWorld Demo Comparison of JavaScript Framework Performance

Предыдущая статьяФункциональные возможности систем типов Julia и Rust
Следующая статьяОбработка ошибок в Go