Open nin-jin opened 4 years ago
Для его отображения воспользуемся компонент $mol_html_view
- в "компонент" опечатка?
На моем телефоне 100-200 статьей открыть - проблема)
В таблице сравнения свроачивания/паджинации/виртуализации строку "Решается ли проблема скорости загрузки", я назвал бы "Решается ли проблема скорости отображения". Т.к. во всех случаях сервер хабра будет грузить все комменты целиком. Но может быть можно добавить столбец "Пагинация на стороне сервера" Хотя там следующая строка про "отзывчивость".
Не понятно как вычислялось количество "=(" в последней строке.
Было бы интересно прочитать раздел про то как делался предварительный анализ.
Спасибо, поправил. Зачем так много статей открывать-то? Имеется ввиду загрузка с точки зрения пользователя. Отображение - тоже двусмысленное понятие. От показа первой страницы до полной загрузки может пройти много времени. =( - это экспертная оценка, её никак не вычислишь. Про предварительный анализ - имеется ввиду алгоритм замера показателей?
На моем телефоне 100-200 статьей открыть - проблема)
опечатлся, имел ввиду 100-200 комментов
Про предварительный анализ - имеется ввиду алгоритм замера показателей?
да, типа как замерял
В какой реализации 200 комментов открыть не удалось?
Добавил в начало информацию по алгоритму замеров.
В какой реализации 200 комментов открыть не удалось?
В мобильной версии хабра, с загрузкой комментов по клику. Обычно примерно так: интересно что в комментах, "клик по 'загрузить комменты'", не большое ожидание и закрытие вкладки
А, памяти не хватает.
кмк на резюме можно словить хейта.
Резюме
- SSR не быстрее грамотной реализации PWA. Вместо поддержки двух абы как слепленных реализаций для разных девайсов, лучше потратить это время на одну, но толковую и адаптивную. Выбирая между двух зол, лучше сделать шаг в сторону - возможно именно там расположилось добро. $mol - рулит, а VueJS - тупит. Браузеру становится очень плохо, когда в доме много элементалей. Стоит предпочитать те решения, что не приводят к не контролируемому увеличению числа элементалей в доме
$mol - рулит, а VueJS - тупит
тут оскорбятся чувства верующих вьюшников хд, что уменьшит количество желающих посмотреть мол
Мб что-нибудь типа, "на вью можно так и ещё хуже, а мол изначально спроектирован так, что бы не делать так(хуже)"
<= Article $mol_html_view
html <= article_content \
highlight <= search
image_uri!node <= image_uri!node \
Возможно стоит добавить комментов, или рядом пример с классом(кажется в классе тоже комменты понадобятся). Т.к. для не знакомых с view.tree, это равносильно чтению аброкадабры. Моск при встрече со сложностью отключится и пролистает дальше(по себе знаю, кмк таких большинство)
Ещё я бы не скупался на упоминаниях о том, что это не язык хтмл шаблонов, а декларативное описание класса
мб вместо =( =( =( =( =( =(
:
6 x =(
или =( x 6
PWA и SSR не совместимы, ибо сервис воркер стартует первым и перехватывает все запросы. Соответственно, его задача - выдать пустой HTML, который отрендерит приложние, которое уже пойдёт за данными. Если он будет идти на сервер за пререндером, то это не будет ничем отличаться от отсутствия PWA.
Если человек прям питает чувства к своему фреймворку, то на $mol он смотреть точно не будет.
Добавил ссылок на описание view.tree. Тут, я думаю, разжёвывать синтаксис нет смысла. По именам можно догадаться что примерно происходит. Ну а даже если пропустить эти примеры кода - в тексте всё равно описывается, что он делает.
Я думал о цифрах, но они не позволяют визуально сравнивать масштабы. Тут смайлики лучше подходят, но они не поддерживаются Хабром ☹☹☹
https://page.hyoo.ru/#!=u4oxgj_q8dpwd
Здравствуйте, меня зовут Дмитрий Карловский и я.. тот ещё токсичный перец. Недавно я источал свои альфа-флюиды на Альфа-банк. Ребята в ответ поступили достойно, и не стали атаковать меня в личку объяснениями, как сильно я не прав, а завели задачу на гитхабе. И даже что-то пофиксили, сделав часть моих претензий несостоятельными. Но не ту часть, где SSR портит всё.
Время утекло, пыль улеглась, и тут история получает продолжение: недавно ко мне обратился продюсер контент-студии Хабра с предложением пропесочить их Торт. Что ж, расчехляем вентилятор!
Сложный случай
Возьмём, например, вот эту страницу, содержащую 2500 комментариев. Это настолько огромная страница, что если вы откроете её в Хроме, то он обрежет её уже на 1400 комментарии. Чтобы прочитать оставшиеся вам придётся открыть её, например, в Огнелисе. Причину этого оставим на совести разработчиков. Давайте лучше подумаем как этого не допустить. Но сперва проведём замеры:
Методика измерений
document.getElementsByTagName('*').length
в режиме наблюдения, приведено максимально наблюдаемое число.Для всех замеров использовался обычный домашний вайфай и ноутбук с развёрнутыми на пол экрана девтулзами. Если что-то не учёл - обязательно докопайтесь к этому в комментариях.
Предварительный анализ
У Хабра есть две версии: десктопная и мобильная. Десктопная загружает статью со всеми комментариями единым HTML. Мобильная же поступает хитрее: сначала загружается статья в виде HTML, а по клику на кнопку "комментарии" она подгружает JSON с комментариями и рендерит их с помощью VueJS вместо статьи. Но если на комментарии зайти по прямой ссылке, то будет загружен пререндеренный HTML. Пререндеренный HTML ничем принципиально не отличается от десктопной версии, поэтому я замерял именно вариант с динамическим рендером, который отрабатывает в большинстве реальных сценариев использования.
Как видно, вес JSON примерно в 4 раза меньше HTML. В формате Tree эти данные весили бы ещё меньше, но парсились бы дольше, ибо кастомный парсер на яваскрипте даже более простого формата всё же медленнее нативного JSON парсера. В любом случае, после сжатия, которое применяется сейчас повсеместно, разница уже не столь существенна - порядка 30%.
Пререндеренный HTML довольно долго грузится, это связано с двумя факторами:
При динамическом рендеринге загрузка данных происходит быстрее, но сэкономленное время компенсируется временем на работу яваскрипта по генерации DOM дерева. В обоих случаях пользователю приходится ждать не меньше полу минуты до возможности прочитать новые комментарии, что крайне долго. Также динамический рендеринг на VueJS не прогрессивен, то есть не позволяет начать чтение контента до его полной обработки.
Всего на страницу выводится около 100K DOM элементов. Это в среднем около 40 элементов на каждый комментарий. Всё это в памяти занимает почти гигабайт.
Браузеру становится очень плохо от такого большого DOM дерева и он начинает серьёзно тупить. Например, обновление экрана при скроллинге, несмотря на его аппаратное ускорение, занимает 700мс. И это чисто скроллинг, без пересчёта лейаута. С ним же - почти 2 секунды. А пересчитывается лейаут почти на любое изменение DOM дерева. DevTools тоже порой сходят с ума, что осложняет профилирование.
Выбор стратегии
Основная причина тормозов - размер DOM дерева. Поэтому требуется такая реализация, которая позволит иметь на пару порядков меньшее число элементов на странице. Выпишем возможные стратегии:
Выводы:
Прототипирование
Самый простой способ воспользоваться виртуальным рендерингом - переписать страницу на $mol, что позволит нам писать код даже не думая о виртуализации, но всё равно её получить, так как в $mol она встроена под капотом.
Хабр возвращает статью и комментарии в виде JSON. Давайте опишем его схему, чтобы тайпскрипт давал нам подсказки и тайпчек, а рантайм проверял, что выдача сервера соответствует ожидаемой. Для этого мы воспользуемся семейством функций $mol_data:
Некоторые поля опциональны - в них возвращается
null
для сообщений, оставленных НЛО.Теперь мы можем легко загрузить данные, проверить их и вернуть типизированную структуру. Например, так выглядит загрузка комментариев:
Хорошо, данные мы загрузили, осталось их показать. Текст статей и комментариев Хабр возвращает в виде строки, содержащей довольно разношёрстный HTML. Для его отображения воспользуемся компонентом $mol_html_view:
(Если вы не знакомы с синтаксисом view.tree, предназначенным для декларативной композиции компонент, то можете ознакомиться с кратким или полным его описанием.)
Этот компонент берёт HTML, парсит его и для каждого элемента создаёт соответствующий $mol_view компонент, а он уже сам себя виртуализирует. Кроме того, $mol_html_view позволяет указать строку, которая будет подсвечена в тексте.
Также нам потребовалось перегрузить метод
image_uri
, который вызывается для каждогоIMG
элемента, чтобы получить ссылку на картинку. Причина в том, что в атрибутеsrc
в выдаче Хабра изначально находится лишь ссылка на заглушку, а реальная ссылка на изображение берётся из атрибутаdata-src
. Поэтому реализуем этот метод так:Рендеринг дерева комментариев не представляет из себя ничего особенного. Разве что мы добавим возможность сворачивать/разворачивать ветки комментариев.
Эта функциональность полезна и сама по себе, но нам она ещё пригодится и для поиска. Дело в том, что $mol пока ещё не умеет прокручивать скролл к заданному компоненту. Штука эта вполне реализуема, но у меня руки пока не дошли, так что если если кто-то возьмётся за это дело - было бы супер.
А сейчас, мы, вместо прокрутки страницы между найденными постами, будем сворачивать все ветки комментариев, где искомая подстрока в тексте не встречается. Таким образом пользователь может ввести запрос и просто скроллить страницу. А при желании - развернуть ветку и почитать все ответы. Выглядит это примерно так:
Многие пользователи привыкли к хоткею
Ctrl+F
для поиска по странице, поэтому добавим плагин $mol_hotkey для его перехвата:Ну а для фокусирования просто доберёмся до нужного нам компонента и скажем ему сфокусироваться:
Обратите внимание, что мы так же добавили плагин $mol_theme_auto, который автоматически ставит светлую или тёмную тему в зависимости от предпочтений пользователя.
Кроме того, добавим пользователю возможность вручную менять тему, разместив на тулбаре кнопку $mol_lights_toggle:
Заодно мы тут расположили стандартную ссылку на исходники и поисковое поле, связав его двусторонней связью с поисковым запросом.
Наведём немного красоты, переопределив некоторые дефолтные стили, используя модуль $mol_style, который обеспечивает тайпчек и подсказки, учитывающие реальную иерархию компонент:
Последним штрихом добавим поддержку оффлайна:
Этим не хитрым кодом мы установили кеширующий Service Worker, который в случае проблем с соединением будет выдавать данные из кеша.
Не то чтобы оффлайн и переключение цветовых тем были необходимы, но если есть возможность практически бесплатно получить вау фичи, которых нет в оригинале, то почему бы и нет.
Что ж, вот наш прототип читалки хабракомментариев и готов: https://nin-jin.github.io/habrcomment/#article=423889
Держите букмарклет, позволяющий открывать в ней любую тяжёлую статью:
Анализ прототипа
Код исходников уложился в 400 строк, на написание которых требуется не более пары часов. По функциональности:
Мы добились ускорения полной загрузки огромной страницы в 5 раз. А потребление памяти уменьшилось в 6 раз по сравнению с мобильной версией (и в 2 раза, если отключить виртуализацию). Для мобилок это куда актуальней, чем для десктопа. При этом мы ещё даже не приступили к собственно оптимизации кода.
Если пошаманить можно выиграть ещё несколько секунд. Например, в наивной реализации HTML всех комментариев парсится при открытии страницы для расчёта их минимальных размеров исходя из содержимого. Однако, можно руками задать какое-то константное значение, меньше которого текст комментария точно быть не может:
Таким образом парсинг HTML будет происходить лишь при фактическом отображении. Позиция скроллбара, конечно, тогда будет рассчитываться несколько менее точно, но это не страшно.
Итого по скорости загрузки мы получили почти десятикратное ускорение полной загрузки при сохранении времени появления контента в 5 секунд. Потребление памяти тоже уменьшилось в 10 раз.
А если есть возможность менять API, то можно пойти ещё дальше - изначально загружать лишь информацию о вложенности комментариев, а собственно информацию по ним загружать лениво, по мере необходимости. Благодаря виртуализации необходимость эта будет возникать лишь при приближении комментария к видимой области. А самое примечательное, что для перехода на ленивую загрузку даже не придётся обновлять вьюшки - достаточно обновить код получения данных. Аналогичным образом легко и переключить клиентский поиск на серверный:
Реализована сейчас, разумеется, не вся функциональность. Но всё остальное особой погоды не делает. Чтобы довести до продакшена, надо будет ещё много чего реализовать. Если кто-то готов этим заняться - можете попробовать. Правда сперва придётся договориться с руководством Хабра об использовании их API. Я пробовал несколько раз подкатить с разных сторон - никакого ответа не получил.
Также можно заметить, что отступы вокруг разных комментариев пляшут как попало - это от того, что HTML, отдаваемый Хабром, это какая-то дичь от слова совсем: слова то в параграфах, то в дивах, то параграфов вообще нет, а абзацы разделяются переводами строк или тегом BR, что вообще вырубает виртуализацию. В общем, тут надо либо чтобы Хабр отдавал что-то единообразное и валидное, либо пилить какой-то свой нормализатор выдачи.
$mol_html_view поддерживает сейчас лишь сравнительно небольшой набор HTML-элементов - далеко не всё, что может выдавать Хабр. Добавить поддержку остальных в принципе не сложно и она, конечно, будет расширяться по мере необходимости.
Кроме того, есть и технические косяки:
А вот появление горизонтального скролла на узких экранах и глубоких обсуждениях - это не баг, а фича. Лучше уж иногда скроллить в сторону, чем вообще терять понимание какой комментарий на какой отвечает начиная с определённого уровня, как это происходит в оригинале. А вот на широком экране мы не ужимаем все комментарии в одну узкую колонку, а занимаем столько места, чтобы их было комфортно читать.
Резюме
Ссылки