Недавно я сделал презентацию на Triangle JS о веб-компонентах и ​​взаимодействии веб-компонентов среди общих UI-фреймворков. Я хотел бы продолжить этот доклад и представить некоторые новые идеи, касающиеся параметров визуализации веб-компонентов и их производительности. Я также предложу несколько примеров реализации, которые решают более сложные задачи рендеринга, такие как рендеринг включенного контента и рендеринг общих веб-компонентов в разных фреймворках.

Тестирование различных реализаций рендеринга JS

Недавний пост на auth0 был посвящен обзору широко используемых JS-фреймворков и дал некоторое представление об их индивидуальной производительности. Впоследствии он был обновлен, чтобы включить в него некоторые метрики для библиотек рендеринга DOM incremental-dom.js и virtual-dom.js. Мне потребовалось время, чтобы воспроизвести эти тесты и проверить результаты, заявленные автором. Я также добавил некоторые показатели для случая, когда пользовательский элемент использовался в шаблоне рендеринга вместе с библиотекой virtual-dom. Следует отметить, что цель этого набора - нагрузочное тестирование работы браузера с каждой библиотекой и предоставление среднего эталонного теста после выполнения пяти тестов с каждой реализацией. Автор также проявил должную осмотрительность, добавив улучшения производительности для рендеринга длинных списков в соответствии с рекомендациями каждой библиотеки (например, выражение Angular track-by).

Потребляемая память

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

Мы также можем увидеть количество основных / второстепенных сборок мусора в Chrome, вызванных каждым фреймворком. Сборки мусора возникают, когда фреймворки создают и уничтожают множество новых ссылок на javascript. Это влияет на другие показатели и заставляет браузер тратить больше циклов на «очистку». Как и ожидалось, мы снова видим сияние инкрементальной модели DOM, поскольку она оптимизирована для алгоритма памяти.

Кадров в секунду

Поддержание высокого FPS - важный показатель при описании производительности фреймворка в сценариях с высоким уровнем рендеринга. Этот показатель, кажется, указывает на то, что большинство фреймворков при максимальной нагрузке колеблются около 50 FPS. Если не соблюдать осторожность, рендеринг с помощью Angular1 может быть совершенно ужасным из-за длинного цикла дайджеста.

Выпавшие кадры

Этот показатель отслеживает количество кадров, пропущенных браузером из-за общей производительности. Мы снова видим проблемы с Angular1 при неправильном использовании. Также есть некоторая визуализация пользовательских элементов воздействия вместо других собственных элементов. Можно предположить, что это связано со временем инициализации настраиваемого элемента, затрачиваемым браузером на создание его определения. Дополнительные комментарии по этому поводу можно найти здесь. Я ожидал, что это улучшится, поскольку браузеры добавят дополнительную поддержку и будут повторять новую спецификацию настраиваемых элементов.

Узлов в макете

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

Общее время выполнения Javascript

Этот показатель отслеживает общее время, затраченное на выполнение Javascript. Здесь снова сияет инкрементальный DOM; за ним следуют cito js и виртуальный DOM.

Выводы по производительности и примечание о Layout / Paint

Я специально не включил метрики Layout / Paint из-за проблемы, описанной здесь. Мне не удалось воспроизвести результаты автора для этого показателя, и оказалось, что более длительное время макета / рисования на самом деле является хорошим предзнаменованием для каждого образца (а не счетчика, как описал автор). Идея здесь в том, что больше времени, затрачиваемого на разметку / отрисовку, указывает на более высокую пропускную способность (которая, похоже, коррелирует с FPS); хотя я подожду подтверждения, прежде чем делать какие-либо предположения.

Мои общие выводы из этого теста:

  1. Каждая из упомянутых структур может работать относительно хорошо при осторожном использовании и при соблюдении передовых практик.
  2. Этот стресс-тест выходит за рамки того, что обычно наблюдается в ваших приложениях, но при определении того, какую библиотеку рендеринга вы хотите использовать в будущих реализациях, полезно увидеть, как работают фреймворки в стрессовых условиях.
  3. Я настоятельно рекомендую вам перейти на новые JS-фреймворки React или Angular2, когда это возможно. Эти фреймворки помогут вам избежать «ловушек» производительности, присущих более старым реализациям, таким как Angular1 или Ember.
  4. Производители браузеров должны продолжать улучшать производительность веб-компонентов. Сделать так, чтобы разработчик создавал DOM так же быстро, как родной DOM, должно быть приоритетом. Похоже, что уже предпринимаются постоянные усилия по улучшению этого на основе спецификации пользовательского элемента v1 для обновлений элемента. Также наблюдается снижение производительности при построении Shadow DOM shadowRoot. А пока мы должны быть более осторожными, чтобы условно отображать настраиваемые элементы только при необходимости.

Некоторые рекомендуемые библиотеки рендеринга и стратегии рендеринга веб-компонентов

Основываясь на этих результатах, я хотел попытаться решить несколько распространенных проблем рендеринга, таких как включение (включение вложенного содержимого в компонент) и привязка шаблона через общие UI-фреймворки AngularJS и ReactJS вместе с веб-компонентами. В этих тестах я также решил исключить Shadow DOM из-за отсутствия в нем поддержки браузера и медленного полифилла. Я включу ссылки, которые могут быть полезны для тех, кто все еще продвигает Shadow DOM.

Изучая ландшафт библиотек, которые используют эти методы рендеринга, я нашел несколько претендентов, которые должны оказаться адекватными для обеспечения оптимального пути рендеринга в веб-компонентах вместе с вашим веб-приложением:

  1. SkateJS: Skate - это библиотека визуализации веб-компонентов, которая использует инкрементную модель DOM для визуализации веб-компонентов. Он предоставляет полезные расширения для упрощения взаимодействия и весит всего 4 тыс. Мин. + Гз. Его основной участник, Трей Шугарт, работает в Atlassian и входит в список участников WebComponents.org среди Google, Microsoft и других.
  2. PreactJS: Preact предоставляет минимальное подмножество реализации виртуальной DOM JS, используемой в ReactJS. Он также имеет полезные расширения для рендеринга HTML-строк ​​и определения пользовательских элементов. Он весит поразительно легкие 3 тыс. Мин. + Gz. Он был протестирован вместе с более тяжелой реализацией virtual-dom.js Мэтта Эша и был очень сопоставим. Учитывая, что эти библиотеки реализуют практически одно и то же решение, я выбрал более легкую альтернативу.

Эти библиотеки должны предоставить отличную платформу для создания оптимальных компонентов в реализациях вашего фреймворка. Прежде чем я углублюсь в несколько примеров и взвесу все за и против, я также хотел бы отметить, что в большинстве случаев вы, вероятно, сможете обойтись без обычного javascript при создании веб-компонентов (как указано в моя презентация Triangle JS). Это также ясно видно на примере источника проекта Onsen.io, уважаемого фреймворка веб-компонентов, который совместим с кросс-фреймворком и хорошо работает в мобильных / гибридных приложениях. Также следует отметить, что эти структуры рендеринга, вероятно, будут желательны только при рендеринге партии DOM внутри компонента.

Включение и привязка к шаблону

Включение позволяет нам взять DOM, визуализированный внутри компонента фреймворком, и поместить его во внутреннюю структуру DOM компонента там, где мы хотим. Учитывая, что пользовательские элементы ведут себя точно так же, как настоящая DOM, в большинстве случаев это довольно тривиально. Я написал пример этого здесь с настраиваемыми элементами и AngularJS, реализующим List View в Patternfly. Я сделал то же самое с React здесь. Что должно стать сразу же, так это то, что часто наблюдаемые шаблоны с Angular, такие как привязки ng-model и циклы ng-repeat, по-прежнему работают с веб-компонентами. Вы также можете легко связывать события и предоставлять средства для отправки сообщений между компонентами.

Основываясь на этом примере, я взял выпадающий виджет (виджет kebab) и реализовал его основную структуру виджета с помощью Preact. Вы можете увидеть это здесь. Что примечательно в этом, я взял выпадающие элементы, отображаемые в DOM, и включил их в метод рендеринга компонентов Preact (его дочерние элементы). Другой подход к этому - использование атрибутов настраиваемых элементов (которые вместо этого передают данные элемента списка). Вы можете увидеть это в действии здесь. Одна из проблем с этим подходом заключается в том, что жизненный цикл компонента Preact, вероятно, не будет соответствовать вашей структуре, поэтому вам нужно будет всегда обеспечивать правильную обработку атрибутов (обратите внимание на попытку / улов атрибута json, который обрабатывает случай, когда данные не пока что обработано Angular). Хотя при осторожном обращении это все же вполне возможно.

Если вы хотите взглянуть на более простой пример, показывающий несколько вариантов использования Preact с Shadow DOM, посмотрите здесь и здесь. Их написал автор Джейсон Миллер.

Похожий пример, который я написал с использованием SkateJS для рендеринга массива данных атрибутов, можно найти здесь. Здесь следует отметить одну вещь, касающуюся Skate: в документации не совсем сказано, что вы должны повторно визуализировать любой включенный контент (легкий DOM) в методе визуализации вашего компонента, поскольку Skate заменит его после его визуализации. цикл. Вам также необходимо предоставить ему несколько параметров для удаления теневого корня Shadow DOM, который он по своей сути реализует. Вы можете увидеть некоторые комментарии о том, как это сделать, здесь.

А что насчет полимера?

Если вы в курсе последних событий в области веб-компонентов, вам, вероятно, покажется забавным, что библиотека Polymer не упоминалась в этом посте до сих пор. Хотя его цель - стать облегченным расширяемым фреймворком, достаточным для создания множества компонентов, я чувствую, что здесь он упустил из виду и сделал слишком много предположений, чтобы большинство авторов фреймворков могли их принять. Как было сказано в недавнем сообщении Роба Додсона, постепенное внедрение веб-компонентов является идеальным для большинства и должно сдерживаться текущими реализациями спецификаций веб-компонентов в браузерах. Хотя большинство поставщиков согласовали и начали реализацию спецификаций Custom Elements, Templates и Shadow DOM (в частности, Safari от Apple), спецификация HTML Imports, на которую в значительной степени полагается Polymer, еще не согласована с другими поставщиками (например, Apple, Mozilla ), и это должно вызывать беспокойство (кто хочет использовать полифил навсегда?). Также очевидно, что методы разделения кода / модуля ES6 могут привести к очень производительным решениям, в том числе с использованием HTTP2 и веб-компонентов, как отмечает Адди Османи из Google. Я также хотел бы отметить, что текущая производительность рендеринга Polymer время от времени подвергалась сомнению и вызвала немало дебатов в Твиттере.

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

Выводы

В заключение, веб-компоненты прошли долгий путь, и некоторые стратегии реализации и взаимодействия определенно начинают обретать форму. Мне бы хотелось, чтобы многие из текущих подключаемых модулей jQuery в Интернете превратились в оптимизированные веб-компоненты, имеющие собственные легкие и производительные реализации, которыми можно легко делиться и расширять между фреймворками. Предоставление этих «листовых» узлов в качестве оптимизированных компонентов с сокращенным набором зависимостей должно сделать их удобными для использования во многих приложениях (например, подумайте, насколько производительным станет древовидное представление с виртуальной DOM). Веб-компоненты также во многом помогают нам инкапсулировать стили и поведение (но я сохраню анимацию для будущего поста).

«До следующего раза!