«Реактивный» интерфейс. Лекция Артёма Белова на FrontTalks 2018

В браузерном JavaScript интерфейсы стали предсказуемы. «Однопоточные», с транзакционным сценарием отрисовки: пустой экран — загрузка — интерфейс. Разработчик Артём Белов из компании Cxense с упором на закон Парето рассказал, как, потратив 20% времени, отрисовать приложение на 80% быстрее за счет приемов «реактивного дизайна» — еще не сформулированных, но уже используемых в продуктах с приоритетом на UX.


Но что касается более матерых парней, которые не вылезают из Webpack и заставляют страдать Webpack, а не наоборот? Они подключают плагины. Но поскольку мы в начале развития этой техники, экосистема нам предлагает плагин, который берет ваш HTML, генерирует на его основе HTML со встроенным CSS, дает QR-код для рекламы… Серьезно? После этого ты можешь взять и через »! important» перебить стили… Пожалуй, стоит задать вопрос, почему я все еще во фронтенде.


— Всем привет, я Артём Белов. В наши дни слово «реактивный» могут понять неправильно: есть большой процент людей, которые выучили React перед изучением JavaScript. Поэтому произносить такие однокоренные слова немного неоднозначно. Ну, а для меня это до сих пор физика, закон сохранения импульса.

Начнем с проблемы. Это наш профессиональный перфекционизм. Ведь мы не показываем интерфейс до того, как он не «идеален» — по нашему мнению. И я не знаю, что выиграет в номинации на информативность: белый экран браузера или спиннер с надписью «Feel free to wait forever»; мне не ясно.

lp6nimmouvk7ykz4jww1kxtbao0.gif

Но одно можно сказать точно: отрисовка, как и отклик приложения — не транзакция. Отображение интерфейса — не логическая единица, так что это нужно бить на порции.

ijyemgrfvrmwrqzfqjuhgij4fv0.png

И во фронтенде, в общем-то, мы помогаем себе, мы завираемся.

xtoqwysiydkejdbgl-5hks8zlss.png

В основном, когда говорим про «время загрузки» нашего приложения, мы не говорим фразу полностью — «среднее время загрузки». Хотя не нужно быть семь пядей во лбу, чтобы вторую загрузку приложения сделать мгновенной, при помощи Service Worker.

И грустно, что Lighthouse поощряет то, что приложение может не подавать признаки жизни и только на последних двух-трех кадрах аудита говорить: «Я вообще-то отрисовываться собралось».

hpdex6uk7jnysvos09h9bmzqjlw.png

И получить под 100 баллов в тесте приложения на performance сейчас — не самое сложное. Google это заметил, спасибо.

nfodyc04egapyj2qguraxrtuqgs.png

И такое емкое понятие, как «Time to Interactive», было разбито на стадии, а именно: «First Interactive», «Time to Consistently Interactive» и «First Input Delay». Если с первыми двумя терминами при помощи Google Translate можно понять, как взаимодействовать и улучшать, то последний можно объяснить при помощи взгляда на main thread браузера.

xld0iivk6nhvadqiitkkno1wf3a.png

Пример. Если сразу после загрузки интерфейса пользователь осуществляет клик по текстовому полю, то может произойти пауза, прежде чем текстовое поле отобразит курсор с возможностью ввода. Всё потому, что main thread был занят, а интерфейс на момент клика казался готовым к взаимодействию.

sehs3rflulvrztgsmqwmiedgseo.png

Все это сводится к тому, что метрики в Lighthouse имеют практически одинаковое время завершения — то время как они должны быть сбалансированы.

r9yiryefiv4vpmmgjz16xjkuk0c.png

«First meaningful paint» должен быть максимально быстрым, «First contentful paint» должен быть за ним, а у «Time to Consistently Interactive» должна быть не такая большая дельта от белого экрана браузера до полной готовности интерфейса.

Разумеется, есть эксперты, которые скажут, что это достигается просто:

«Нужно разбить приложение по роутам в Webpack и сделать Server-side rendering. Да тут работы на полчаса!»

Но это не совсем так… Уважаемый эксперт не упоминает, что каждый новый роут происходит одно и то же — загрузка. И снова все метрики в Lighthous» имеют малую дельту между собой, ведь роут, как правило, весомый.

И иногда не работаешь в большой успешной компании, и Server-side-рендеринга там нет. И, пользуясь служебным положением, приступаешь к R&D с понятной целью — получить прогрессивный рендеринг. Как прогрессивный JPEG, что в 167 параграфе «Ководства» Лебедева.

В принципе, R&D-план выглядит очень просто… Нужно каким-то образом получить профит. И не забывать о главном — о времени и сроках, которые любят гореть. И, держа манифест минималиста-программиста в руках, ты должен помнить: трать 20% времени на 80% результата.

Я заручился инструментами. Например, lag-radar.

meuigirky5fida7bawgkzjkrhq4.gif

Правда, я не углублялся в Санта-Барбару, кто украл идею, Дэн Абрамов у кого-то или наоборот… На последней презентации JSConf Iceland 2018 была показана довольно интересная концепция: радар зеленый до того момента, пока не обнаруживает задержки в main tread, и когда они чувствительные — радар становится желтым, а когда критичные — красным.

И, нажав Cmd+Shift+P на Mac — или Ctrl+Shift+P на Windows, — я посмотрел на процент покрытия кода. А потом посмотрел на бандл.

qmzpxh1534fuw7wmb12pcahwbu0.png

n9kbb4yn0tr_elsgaqcjmxoabsi.png

И опять на покрытие, и опять на бандл. И попросту решил принять ситуацию. Мне не нужно ничего отсюда убирать. Ведь в проектах многие используют инструменты, которые являются стандартами де-факто. Например, Иван Акулов совместно с Google Chrome Labs давным-давно сделали репозиторий по оптимизации вебпака, webpack-libs-optimizations. И зачем мне это повторять, рассказывать про Сode Split, про Lazy load? Это то, что является известными и прогрессивными стандартами в 2018-м.

blhqsfhtguvdph0phjugkxdii8k.png

И отвечая на вопрос «А что можно загрузить за полсекунды?» — JS и тут победитель. Например, можно загрузить 100 килобайт JPG и потратить 0,04 на его обработку, но JS его уделывает, ведь на его обработку нужно гораздо больше времени, в 20 раз.

i52tbfz_iunvezbqv4inaps2gbu.png

Потому что надо помнить, что происходит во время старта приложения.

zgma2bclq-utain_9wewam-znea.png

После загрузки начинается та вещь, которую хочется докомпозировать: загрузить в один момент, а парсинг, компиляцию и исполнение кода произвести в другой момент времени.

utaccnuew-ezap0uwwa5gwdeptm.png

Я посмотрел, что предлагает нам тег