Комментарии на Хабре иногда несут больше пользы, чем сама статья. Поэтому при переходе на новую версию сайта было важно сделать работу с комментами не хуже, чем было.
Вы когда-нибудь открывали в старом дизайне Хабра пост с большим числом комментариев? Страничка даже с тысячей сообщений грузится шустро, на ней без серьёзных задержек работает форма для ответа, кнопки голосования и закладок. Но когда мы начали переход на новую версию Хабра, стало понятно, что добиться такой же скорости будет непросто.
Этому есть несколько причин. Во-первых, Хабр стал одностраничным приложением (SPA, Single Page Application) на Vue, то есть теперь переходы между страницами рисуются на клиенте с помощью JS вместо классического серверного рендеринга (Server-Side Rendering, SSR). Такие SPA-страницы отображаются быстрее на современных устройствах, но на старых девайсах могут тормозить.
Во-вторых, движок старого Хабра — это больше десяти лет оптимизаций, костылей и заплаток. Вполне естественно, что если попытаться переписать их с нуля на современных технологиях, придётся учесть эту историю поиска и устранения бутылочных горлышек в производительности.
В октябре мы постепенно выкатывали на часть пользователей обновлённую версию комментариев, над которой трудились последние полгода. Наши новые комментарии должны рендериться быстрее и доставлять удовольствие всем, а не только обладателям топовых MacBook Pro c M1 Max.
Давайте посмотрим, как работали комментарии полгода назад, до того, как мы начали работу по оптимизации.
Полгода назад в угоду производительности комментарии «прятались» на отдельной странице за одноимённой кнопкой. Да, это не всегда удобно, особенно если вы привыкли к старому Хабру, где обсуждения выводились прямо под статьёй. Зато статья загружалась сразу, прогрузки комментариев для её чтения ждать не приходилось.
Та самая кнопка
Второе неудобство: простое открытие страницы с комментариями в новой вкладке иногда растягивалось на десятки секунд. Это уже связано с тем, что серверный рендеринг — операция дорогая. Кэширование SSR работало только для гостей и с низким сроком жизни.
Ну и в-третьих, навигация по сайту в режиме SPA (без перезагрузки страницы) оставляла желать лучшего. Если у вас медленный смартфон, то вы имели шанс вообще не увидеть комментарии: память кончалась быстрее, чем успевали отработать скрипты и рендеринг.
Мы провели глубокий анализ проблем с комментариями и нашли несколько решений по ускорению рендеринга. Наша задача подразумевала максимальные улучшения ценой минимальных усилий. Поэтому всю работу мы разбили на три итерации, повышая сложность каждый раз, когда решений попроще уже не хватало.
За шесть месяцев мы перепробовали многое — сегодня рассказываем про результат и путь к нему.
Первая итерация: принудительный SSR
Чтобы что-то улучшать, нужно это измерить. Для начала мы замерили скорость отрисовки комментариев на клиенте и на сервере. Оказалось, что мобильные устройства сильно проигрывают по скорости серверу, когда число комментариев переваливает за сотни. График ниже показывает, в какой момент это случается.
Общее время для загрузки комментариев
Чтобы создать ощущение, что комментарии рисуются быстрее, с определённого порога нужно переключаться на исключительно серверный рендеринг. Для этого мы создали условие: по достижению 600 комментариев страница должна загружаться именно через серверный рендеринг.
Но просто заставить некоторые страницы рисоваться сервером было недостаточно. Такой временный отказ от SPA нужно было сделать максимально незаметным для пользователя, который привык к тому, что нажатия по ссылкам приводят к мгновенным переходам.
Ленивая гидратация
Чтобы запустить приложение Хабра, всю разметку с сервера необходимо «гидрировать» на клиенте, иными словами — убедиться, что отрисовалось именно то, что нужно. Но нет никакого смысла пытаться на старте приложения проверять абсолютно все комментарии на корректную отрисовку, потому что пользователь своими глазами видит лишь малую их часть.
Нам повезло, что существует готовое решение этой проблемы: vue-lazy-hydration. Этот компонент умеет «откладывать» гидратацию и принудительно запускать её по определённым правилам. Мы взяли за основу стратегию, которая работает через Intersection Observer: она проверяет, что элемент попал во вьюпорт, и только тогда запускает процесс его гидратации.
Улучшения оказались значительными. После применения такой оптимизации запуск приложения ускорился в 5–10 раз в зависимости от количества комментариев.
Предотвращение избыточной перерисовки
Производительность на клиенте вырастет, если предотвратить избыточную перерисовку страницы (forced reflow).
Мы обратили внимание, что используемая библиотека vue-check-view обращается к свойству window.pageYOffset слишком рано, причём на всех страницах. Из-за этого перерасчёт стилей происходил фактически два раза: до запуска приложения и после.
После отказа от этой библиотеки и переписывания кода на Intersection Observer время перерасчёта стилей упало в два раза.
Вторая итерация: рендеринг на клиенте
Наконец-то мы включили отрисовку комментариев прямо под статьёй, но не везде, а где их меньше 300. Предыдущие замеры говорили, что такая отсечка — решение разумное: жизнь на медленных устройствах этот переход не испортил бы.
Ленивый рендеринг
При этом комментарии под статьёй рисовались не серверным рендерингом. Пойти на это пришлось, чтобы открывшему статью читателю не приходилось ждать впустую отрисовки комментариев, что в свою очередь будет замедлять отрисовку статьи.
Мы в очередной раз взяли Intersection Observer и возложили рендеринг комментариев под статьй исключительно на браузер. Отрисовка вызывалась только тогда, когда пользователь действительно закончил читать статью и был готов перейти к комментариям.
Так мы и серверные ресурсы сберегли, и взаимодействие с комментариями сделали приятней.
Content Visibility
В арсенал схватки за производительность попало новое свойство CSS: content-visibility.
В упрощённом объяснении работа этого свойства очевидна. Пока элемент находится во вьюпорте, браузер рассчитывает для него все три фазы отрисовки — layout, paint и composition. Как только элемент исчезает из вьюпорта, то эти фазы перестают выполняться.
Это приводит к неприятному эффекту: интерфейс начинает прыгать. Так происходит потому, что высота элемента в этот момент становится нулевой и, соответственно, интерфейс перестраивается с учётом этой высоты. Чтобы избежать прыжков в интерфейсе, есть отдельное свойство contain-intrinsic-size, которое позволяет указать размеры элемента и, таким образом, сохранить корректное положение остальных элементов.
Применение этого свойства для элементов с фиксированной высотой (шапка и футер комментария) позволило нам ускорить фазу layout у отрисовки комментариев примерно в 2 раза.
На этом вторая фаза наших оптимизаций подошла к концу, и простые решения закончились. Осталось самое интересное.
Ушли проблемы с долгим запуском приложения, с долгой отрисовкой и долгой загрузкой комментариев. Осталось уравнять наших пользователей в тех вопросах, когда доходило до отрисовки комментариев на клиенте, и рендерить комментарии под каждым постом.
Одна из важнейших вещей, которая влияет на ощущение скорости (именно ощущение, а не абсолютные цифры) — это то, как быстро мы можем увидеть какой-то полезный контент, будь то КДПВ или текст комментария. Достигается это за счёт устройства HTML: он изначально спроектирован так, что содержимое можно отдавать по кусочкам (стримить) и при этом всё равно получать какой-то понятный результат в процессе загрузки.
При переносе рендеринга на JavaScript эта фича теряется — все современные фреймворки рендерят контент синхронно. Некоторые применяют хитрые оптимизации вроде Reconciler, но рендеринг принципиально остаётся синхронным.
Синхронно — это плохо: пока все комментарии не отрисуются, ни одного из них видно не будет. А если совместить удобство использования JS-фреймворка и отличный UX, который нам из коробки даёт HTML?
Встречайте: стриминг-рендеринг комментариев!
Третья итерация: стриминг-рендеринг
Не самая это простая задача — заставить приложение рисоваться на клиенте так, будто грузится обычный HTML.
Принцип работы
Все современные JS-фреймворки предлагают как минимум два варианта рендеринга HTML на сервере: синхронный (целиком одной строкой) или стриминг.
Возникла идея: а если перенести часть нагрузки с клиента обратно на сервер и сделать это точечно, только для тех мест, которые требуют больших ресурсов? Тогда бутылочным горлышком будет уже сеть и мощности сервера, а не возможности устройства.
Но как визуально повторить стриминг HTML при начальной загрузке документа, только в этот раз уже для конкретного куска приложения? На помощь пришла статья Джейка Арчибальда, который показал, как это реализовать с помощью iframe. Трюк заключался в том, чтобы обновлять документ iframe, но при этом сам элемент отрисовки переместить в основной документ. Визуально это ничем не будет отличаться от обычной загрузки документа.
К сожалению, метод с iframe на сегодняшний день перестал работать в некоторых браузерах и сильно тормозил в Chrome. Мы не теряли надежду и попробовали ход конём: создать новый документ в нашем документе.
Разработчик Хабра предлагает новый метод рендеринга
Удивительно, этот метод заработал стабильно во всех браузерах, причём быстро. Но для полноценного перехода на стриминг этого было всё ещё недостаточно.
Камнем преткновения стала проблема гидратации разметки на клиенте: после отрисовки нужно взаимодействовать с комментариями. Эту проблему мы решили путём долгого и скрупулёзного изучения исходников Vue — оказалось, что можно принудительно гидрировать элемент, если в нужный момент заменить скрытое свойство
_vnode
. Именно с помощью этого свойства Vue способен определить, нужно ли гидрировать текущий компонент. Если вместо VNode (структура виртуального DOM) там находится реальный DOM-элемент, то Vue запускает процесс гидратации. В нашем случае мы подставили в _vnode
элемент с комментариями, который только что закончил стримиться.Через несколько недель был готов proof of concept, наглядно показывающий преимущества стриминга над обычным рендерингом на клиенте:
Кэширование
Доработка кэширования комментариев стала следующим шагом и позволила вывести производительность до желаемых показателей.
До этого комментарии кэшировались только для гостей и ненадолго. Фреймворк, который мы используем для отрисовки интерфейса (Vue), предоставляет возможность кэшировать наше приложение по кусочкам (с помощью опции serverCacheKey), что отлично подошло для улучшений.
Мы добавили уникальный ключ состояния в API получения комментариев и стали использовать его в
serverCacheKey
. Redis взял на себя задачи сервиса хранения кэша. Это самое простое и надёжное решение: например, с ним нет никаких проблем использовать один и тот же кэш на разных инстансах SSR. Redis также существенно сократил ответ сервера для стриминга комментариев: при наличии ключа для кэша в запросе не нужно даже стартовать приложение, достаточно сразу начать стримить кэш. Таким образом, получилось отделить кэш комментариев от отрисовки всего остального интерфейса, что важно для длительного хранения кэша.Но радоваться было рано. Мы сразу же наткнулись на вторую настоящую проблему в Computer Science: инвалидацию кэшей. Дело в том, что до этого комментарии для авторизованных пользователей и для гостей рисовались по-разному. Такой подход вводил существенные ограничения в применении кэширования, потому что нужно было выбирать между двумя плохими вариантами: либо оставлять авторизованных пользователей без кэширования, либо описывать все виды состояний, которые могут быть у комментариев.
Мы взвесили эти варианты, поняли, что ни один из них нас не устраивает, и принялись брейнштормить, как решать эту проблему.
Решение вскоре нашлось: можно всегда рисовать комментарии в представлении для гостя, а интерфейс для пользователя достраивать уже на клиенте. Так мы отвязали наши кэши от сессии пользователя и сделали их общими для всех пользователей независимо от их роли. Такой подход хорошо сочетался с уже описанным vue-lazy-hydration: перерисовывались только те элементы интерфейса, которые пользователь видит своими глазами.
Сопутствующие проблемы
Внедрение стриминг-рендера для комментариев не прошло безболезненно. Всплыли ещё куда более интересные проблемы.
Якорные ссылки
Поведение якорных ссылок пользователю хорошо известно: сначала загружается весь документ, затем браузер сам скроллит до нужного элемента. Но с переходом на стриминг этот механизм сломался: такого поведения «из коробки» нет, потому что на момент перехода по такой якорной ссылке комментарии попросту отсутствуют.
На первый взгляд, у этой проблемы есть очевидное решение: прокручивать к нужному элементу программно, когда все комментарии будут загружены. Но, к сожалению, это противоречит сути стриминга: чтение можно начать, не дожидаясь того, как вся страница будет загружена. Пусть пользователь находится где-нибудь посередине страницы, когда загрузка будет завершена. Если в этот момент проскроллить страницу до комментария, куда вела якорная ссылка, то текущая позиция чтения будет утеряна, что может вызывать сильное раздражение у читателя. То же самое может произойти если попытаться перезагрузить страницу.
К решению этой проблемы мы подошли с другой стороны: с якорными ссылками лучше всего довериться самому браузеру. Для всех якорных ссылок сделали условие загрузки страницы только с помощью SSR. С наличием кэширования в комментариях такой подход вполне имел право на жизнь: ждать страницу статьи и комментариев с серверным рендерингом приходилось значительно меньше, а приложение Хабра стартовало уже достаточно быстро.
Восстановление скролла при перезагрузке страницы
Стриминг ломает ещё одно привычное поведение браузера — сохранение позиции скролла при перезагрузке страницы. Все те проблемы, что я описал выше, также актуальны и здесь. Происходит это ровно по той же причине: комментариев не существует на момент, когда браузер может восстановить скролл.
Мы не стали изобретать велосипед и снова доверились браузеру. Правда, решение этой проблемы получилось чуть сложнее, чем принудительный SSR для якорных ссылок. Нужно было понять, когда комментарии рисовать на сервере, когда — на клиенте.
На помощь пришли куки, с помощью которых сервер узнавал, что пользователь посещал эту страницу. Куки с настройкой устанавливается, когда пользователь в первый раз открывает статью, и очищается, когда он уходит с неё.
Таким образом, при первом визите статья открывалась максимально быстро. При этом для пользователя стриминг встраивался совершенно незаметно: он мог обновить страницу и продолжить чтение комментариев с того места, где остановился.
Неизвестная высота скролла
Один из неизбежных минусов стриминга: невозможность узнать конечную высоту скролла для всей страницы до завершения стриминга. Это становится реальной проблемой, когда комментариев так много, что ползунок скролла стремительно уменьшается. Пользоваться им становится сложно, особенно если в этот момент вы уже с ним взаимодействуете и совсем не ожидаете изменения его позиции или размера.
Чтобы решить эту проблему, мы решили ограничить высоту комментариев во время стриминга, с возможностью показать все комментарии по клику на кнопку. Такое решение добавило предсказуемости в интерфейсе. Чтобы нажать на кнопку, нужно прекратить взаимодействие со скроллом, и понятно, что это действие повлияет на скролл.
Навигация Назад/Вперёд
Ещё одно совершенно привычное действие для классических веб-сайтов: навигация по страницам с помощью кнопок «Вперёд» и «Назад». В SPA-режиме такое поведение по сути приходится переизобретать с помощью JS, заново описывая поведение браузера, отточенное годами. Одно из таких поведений — это восстановление позиции скролла при навигации назад/вперёд. Да, мы снова поговорим про скролл, только на этот раз проблема будет куда обширнее и сложнее.
При навигации назад/вперёд браузер использует так называемый back/forward cache. Если коротко: браузер держит в памяти страницы, которые вы посещали, и при навигации туда-сюда может их моментально восстановить ровно в том состоянии, в котором вы с них ушли. При переходе на SPA эта ответственность лежит на плечах самих разработчиков.
Для простых случаев этого не так уж и сложно достигнуть: необходимо хранить в памяти позицию скролла и кэш данных. Тогда при возвращении на предыдущую страницу мы отрисуем её заново, но ровно в таком же виде, в котором мы её видели в последний раз. Это отлично работает (до тех пор пока у вас нет стриминга).
Последнее, чего хочется при наличии стриминга — это заново рисовать страницу: стриминг рисует страницу не сразу, а по кусочкам. Соответственно, если необходимо восстановить скролл, то нужно дождаться момента, пока стриминг закончит свою работу и только потом пытаться скроллить до нужного места. Но это приведёт ровно к тем же проблемам, что я описал выше: пользователь может начать скроллить до того момента, как стриминг закончит работу. К тому же вновь придётся делать много лишней работы: выполнять отрисовку каждый раз, когда вставляется новый кусок комментариев, строить VDOM-дерево, гидрировать видимую часть комментариев и так далее.
К счастью, всего этого можно избежать, если использовать компонент keep-alive, встроенный во Vue. Он хранит в памяти элемент и состояние компонента, даже когда он исчезает из VDOM, и восстанавливает его, когда он туда возвращается. Мы выборочно применили его для страницы со статьёй и получили желаемый эффект: статья и комментарии остаются ровно в том же состоянии если к ним вернуться через навигацию назад\вперёд.
Радость была недолгой. Как станет ясно дальше: чтобы keep-alive работал в приложении без изъянов, компоненты нужно изначально проектировать с учётом наличия keep-alive.
Сначала внезапно стал пропадать кэш страницы. После многочасовых сессий отладки стало понятно, что те компоненты, которые лежат в кэше keep-alive, продолжают работать. Это значит, что будут пересчитываться вычисляемые свойства, вотчеры. В целом этот компонент ничем не будет отличаться от обычного компонента вне keep-alive, просто его элемент не будет отображаться в документе.
Идентификатор статьи, который брался из параметров текущего роута, был одним из таких вычисляемых свойств. Естественно, когда мы заходили в другую статью, это свойство также рассчитывалось и для старой статьи, которая лежала в кэше keep-alive. Это и приводило к сбросу кэша: кэшированный элемент уже не совпадал с новым VDOM, который сгенерировал компонент.
Решение оказалось простым: вместо использования реактивных свойств роута нужно передать параметры текущего роута через пропсы (входные параметры компонента). Тогда они будут зафиксированы для этой страницы, даже если мы перейдём на такую же с другими параметрами.
Вторая проблема заключалась в том, что обработчики событий в скрытых компонентах продолжали работать. В том числе работали и глобальные обработчики событий, например, для горячих клавиш. Это приводило к тому что горячие клавиши поста срабатывали с совершенно другой страницы.
То же самое касалось и любых вотчеров, которые могли запрашивать данные или показывать какой-то интерфейс при изменении глобального состояния. Для таких случаев во Vue предусмотрен флаг
_inactive
, который сигнализирует о том, что компонент скрыт и лежит в кэше keep-alive. Пришлось добавить этот флаг во все участки кода, где мы полагались на глобальное состояние или глобальные обработчики событий.В итоге от keep-alive создалось двоякое ощущение: можем эффективно решить проблему навигации назад\вперёд, но сложность компонентов и ad-hoc решений из-за этого постоянно повышается. На сегодняшний день мы продолжаем искать замену keep-alive на что-то более удачное.
Первые результаты
Казалось бы, стриминг должен был и в абсолютных числах показать существенное улучшение. Но тут нас ждал сюжетный поворот похлеще, чем у Шьямалана.
Стриминг работает быстрее, чем обычный SSR, но медленнее рендеринга на клиенте. Вот наглядный график сравнения скорости клиентского рендеринга со стримингом и SSR (оба без кэширования):
Со стримингом появляются дополнительные издержки на работу с буфером строк, backpressure (как на сервере, так и на клиенте) и сетью, чего нет при классических подходах. Ну и при каждой вставке нового куска HTML нам нужно вызвать перерасчёт стилей и layout всей страницы. Если не следить за руками, то ресурсов это ест много.
Почему же мы с такой гордостью рассказываем про стриминг, если по факту для пользователей комментарии стали рисоваться медленнее? Всё потому, что когда мы пытаемся улучшить пользовательский опыт, в первую очередь нужно ориентироваться на ощущение скорости, а не на абсолютные числа.
Мы можем рисовать комментарии за 5 секунд, но эти 5 секунд пользователь будет видеть вместо них заглушку. Или комментарии будут готовы за 10 секунд, но вместо заглушки пользователь может сразу начать читать комментарии. Поэтому важно не просто оптимизировать цифры в вакууме, а именно создавать ощущение ускорения.
Ещё одной важной особенностью стриминга является то, что результат его работы можно эффективно кэшировать. График выше показывает ситуацию, когда мы не попали в кэш, но в реальности (графики будут дальше) стриминг будет почти всегда быстрее клиентского рендера именно из-за кэширования.
Хочу отметить, что стриминг-рендер — не панацея и подойдёт не для всех.
В первую очередь он увеличивает нагрузку на сервер: то, что раньше рендерилось на клиенте, уйдёт на сервер со всеми вытекающими последствиями. Также он может существенно увеличить объёмы трафика, которые придётся пересылать. Мы прочувствовали это на собственной шкуре, когда выкатили стриминг в первый раз и не рассчитали нагрузку на нашу инфраструктуру.
Только после существенной доработки мы оставим стриминг в продакшене. Стриминг включается только тогда, когда комментариев больше 300. Комментарии по-прежнему рендерятся тогда, когда пользователь до них доскроллил. Всё это сделано именно в рамках экономии ресурсов.
Возможно, когда-нибудь эти ограничения получится снять, если вынести стриминг-рендер в воркер. А впрочем, это уже совсем другая история…
One more thing
Расскажем о наших неудачах в процессе поиска решений для ускорения комментариев.
Content Visibility для всего комментария
Нам настолько понравилась скорость работы комментариев с content-visibility, что был велик соблазн использовать его для всего комментария. Тут мы наткнулись на нерешаемую проблему со скроллом: им попросту невозможно было пользоваться, так как высота комментария постоянно прыгала и не поддавалась лечению, несмотря на наши усердные попытки. К тому же это напрочь убивало переходы по якорным ссылкам, тем более — плавные переходы.
Мы извлекли чёткий урок из этой истории: не пытайтесь навесить content-visibility на элементы, высоту которых вы не знаете заранее.
Функциональные компоненты
Так как наше приложение написано на Vue, то один из негласных способов ускорения рендеринга — использование функциональных компонентов.
Это действительно так — функциональные компоненты ускоряют отрисовку компонентов примерно на 20–30%, но такое ускорение не проходит даром. Их тяжело поддерживать — особенно если они написаны через функциональные шаблоны, как в нашем случае. Ещё хуже обстоят дела с тем, что всё состояние функционального компонента куда-то должно переместиться.
В нашем случае это был общий родитель всех комментариев. Это плохо, поскольку, к примеру, голосование за один комментарий приведёт к перерисовке вообще всех комментариев. В итоге немного оптимизировали в одном месте, но существенно деоптимизировали в другом.
В конечном счёте мы полностью отказались от функциональных компонентов и пришли к стримингу.
Time slicing
Этот подход отличается от нашего стриминга — в слайсинге работа делится на кусочки исключительно на клиенте.
Тайм-слайсинг действительно имеет право на жизнь, но у него есть несколько существенных недостатков. Он работает ещё медленнее, чем обычный рендеринг, слабые устройства по-прежнему будут страдать. Наверное, главная его проблема — сложно разбить эту работу на равномерные куски.
Так как неизвестно, как долго будет рендериться конкретный комментарий, нет гарантий, что не будет зависаний в процессе такого рендера. В итоге опыт будет ещё хуже, чем с ожиданием полного рендера всех комментариев: мы делаем вид, что комментариями можно уже пользоваться, но интерфейс может затормозить в любой момент.
К тому же результат такого рендера невозможно закэшировать, в отличие от стриминга с сервера. Добавляем к этому все проблемы стриминг-рендера, которые нам нужно будет решить: якорные ссылки, скроллинг и так далее. Сразу станет понятным, что стриминг-рендер гораздо интереснее, чем тайм-слайсинг.
Стриминг всей страницы
Казалось бы, это такой low hanging fruit: убираем SPA-режим из приложения и вместо синхронного SSR в готовую строку начинаем стримить нашу разметку для всех страниц. Поначалу действительно так может показаться, пока не вдаёшься в детали.
Проблема заключается в том, что не все участки приложения грузятся в том порядке, в котором они попадают на клиент. Например, заголовок страницы будет известен только тогда, когда дело дойдёт до компонента со статьёй, или появляется портал, который рисует компонент в совершенно другом участке приложения. Вот ещё один частый кейс: необходимо сделать редирект, зависящий от данных, которые приходят асинхронно.
Конечно, для всего перечисленного есть обходные пути, но они накладывают существенные ограничения на архитектуру приложения. Пока что такой сдвиг показался нам нецелесообразным.
Вторая проблема, не менее серьёзная: если во время стриминга что-то пошло не так, то из этого состояния невозможно восстановиться. Стриминг может остановиться в любом участке кода, в том числе на незакрытом теге. Непонятно, как в такой ситуации гарантированно помочь пользователю хотя бы обновить страницу.
Я уверен, что в будущем фреймворки будут сильнее фокусироваться именно на стриминге (в React уже активно думают в эту сторону). В какой-то момент он станет first class citizen и все эти проблемы будут решены. Но пока что синхронный SSR — это лучшее из того, что у нас есть.
Итог
Напоследок покажем сравнение того, сколько занимала отрисовка страницы с 800 комментариями до оптимизации и после:
Видео
Демонстрация работы
Десктопный SPA
Мобильный SSR
Мобильный SPA
Десктопный SSR
Десктопный SPA
Мобильный SSR
Мобильный SPA
Графики
Наглядно
SSR
Клиентский рендеринг
До | После |
Клиентский рендеринг
До | После |
В работе принимали участие:
- Фронтенд-команда: Станислав Лашманов, Таиф Алимов, Виталий Сорокин, Александр Груздков
- Бекенд-команда: Антон Каракулов, Артём Константинов, Иван Дударев
- Команда контроля качества: Никита Сапун, Николай Баутин
- Дизайн-команда: Кира Воеводина, Степан Воеводин
- Технический директор: Дмитрий Колобов
- Менеджер продукта: Сергей Фомин
- По текстам: Алексей «Boomburum» Шевелев, Вииииика «The greatest» Гонгина & Анатолий Будько aka Atomlib
Если хотите/любите/умеете решать интересные задачи во блага миллионов пользователей, то обратите внимание на наши вакансии.
→ А ещё посмотрите на наш конкурс технических статей — Технотекст 2021.
А как вам работа новых комментариев? Расскажите в комментариях :)