![image](https://habrastorage.org/getpro/habr/post_images/9c3/863/ef7/9c3863ef729ab03d53558b942c8b8c02.png)
Тогда в качестве шаблонизатора мы использовали XSL, а данные передавали в формате XML. Переведя проект на новый интерфейс, мы начали искать другие способы ускорения работы интерфейса Яндекс.Почты.
Недавно мы перевели всю Почту на JS-шаблонизатор и JSON-данные.
Причины отказа от XML/XSL
Мы очень любим XSL, он выразительный, на нём действительно удобно писать шаблоны для крупных сервисов со сложными связями, большим количеством повторно используемых блоков и возможностью переопределять или доопределять блоки. Но есть у него и ряд существенных недостатков:
- Не развивается
Если посмотреть багтеркеры браузеров, то последние затронутые разработчиками упоминания об XSL датируются 2004 годом (особенно очевидна проблема в Хроме на графиках ниже).
- Большое количество проблем в реализациях для различных браузеров
Во-первых, реализации, как всегда, отличаются в IE и не в IE. Есть пара очень неприятных проблем в Опере, как, например, игнорирование первогоxsl:call-template
и сложными предикатами, а иногда — загрузка картинки до трансформации. Хром требует отличного от других браузеровxsl:output
. - Сложно отлаживать
Самым популярным способом диагностирования проблем является комментирование кусков шаблона. - Сложно профилировать
XSL-процессор в браузере — чёрный ящик, и говорить о том, какие конструкции работают быстрее, а какие медленнее, можно только на основе косвенных суждений, полученных на синтетических тестах. - Cложно расширять
Если использовать xslt на сервере, то там ещё можно подключить exslt, в браузере же приходится сильно исхитряться со стандартными средствами, чтобы как-то нестандартно обработать строки. - Трудно обрабатывать XML-данные на сервере
Если нужно изменить выдачу перед попаданием на клиент, придётся использовать E4X – да, у нас spidermonkey. E4X на самом деле не очень удобный и уж точно не очень быстрый по сравнению с модификацией JSON.
Выбор нового шаблонизатора
Мы пробовали разные (как по семантике, так и по синтаксису) шаблонизаторы, в том числе: yate, handlebars, jade, dust и ajaxslt.
Имея json-выдачу и все необходимые данные для формирования списка писем, мы попробовали использовать каждый из вышеперечисленных шаблонизаторов.
Поскольку страница со списком писем использует наибольшее число из всех доступных составляющих почты (папки, метки, сборщики, фильтры, треды, ну и сами письма), мы сразу смогли проверить каждый шаблонизатор под максимальной нагрузкой на скорость работы/отрисовки. Также принимали во внимание удобство разработки и простоту поддержки кода в дальнейшем.
Почти сразу стало очевидно, что императивные шаблонизаторы (handlebars, jade, dust) не могут сравниться по удобству разработки с декларативными, их код превращался в «кашу», в которой всё сложнее было разбираться. К тому же мы привыкли к гибкости XSL и сильному разграничению данных и логики отображения, поэтому нам было удобнее работать с шаблонизаторами похожей семантики.
Таким образом, в финале оказались yate и ajaxslt. Но, несмотря на все старания наших разработчиков, ajaxslt не смог приблизиться к производительности yate и требовал больше 500 мс на преобразование.
Итоговый зачёт по скорости отрисовки списка из 200 писем выглядел так:
![image](https://habrastorage.org/getpro/habr/post_images/3e5/7b7/040/3e57b7040663e048f56067c4e7261ef3.png)
Yate
Yate — проект, созданный и развиваемый фронтэнд-архитектором Почты. Этот шаблонизатор уже успешно зарекомендовал себя на нескольких готовых, но ещё не представленных проектах Яндекса. Yate очень похож на XSL: при более лёгком и js-подобном синтаксисе в нём используются те же парадигмы (match, apply), поддерживаются предикаты, а также есть jpath — аналог XPath для навигации по JSON. Шаблоны компилируются в обычный javascript и использовать их можно как на клиенте, так и на сервере.
Вот так выглядит один и тот же шаблон на XSL и на yate:
![image](https://habrastorage.org/getpro/habr/post_images/5b5/873/090/5b5873090323bde0c238bc8d46c9b3dc.png)
Для нас огромное значение имеет скорость работы интерфейса, поэтому мы были рады, когда yate показал очень хорошие результаты скорости рендеринга шаблонов — получилось, что реализованный на JavaScript процессор работает быстрее встроенного в браузер XSL-процессора. Кроме того, учитывая, что с каждой новой версией браузера JS становится всё быстрее и функциональнее, разрыв будет только увеличиваться.
Только начав использовать yate, мы выиграли в скорости трансформации от 40% и более, в зависимости от браузера. В случае с Хромом выигрыш составил… 1200%!
Но нам показалось, что этого недостаточно.
Ведь скомпилированный шаблон – это обычный JS-код, который легко анализировать профайлером, имеющимся в любом браузере:
![image](https://habrastorage.org/getpro/habr/post_images/c4f/058/196/c4f0581962eb6b997be30318169f24cf.png)
А это значит, что его можно исследовать и оптимизировать, добиваясь тем самым ускорения его работы.
В итоге мы отыграли ещё пару миллисекунд, обнаружив и оптимизировав самые тяжёлые шаблоны, а также посмотрели, какие операции в скомпилированном шаблоне выполняются чаще всего, и подправили компилятор так, чтобы он сразу генерировал оптимальный для таких операций код:
![image](https://habrastorage.org/getpro/habr/post_images/de9/5cc/2f2/de95cc2f287a9557f070867bc203c9a1.png)
Стоит отметить, что все исследования мы проводили на максимальном количестве писем на странице – 200. По умолчанию у пользователей 30 писем на странице, а на таких объёмах шаблонизация проходит ещё быстрее:
![image](https://habrastorage.org/getpro/habr/post_images/cb6/84e/2a7/cb684e2a7d9436bd00a48cc800bf60f2.png)
Существенно упростилась и отладка — если что-то прошло не так, достаточно вставить
debugger
в скомпилированный шаблон и посмотреть, в чём проблема. Также можно воспользоваться встроенной функцией log
, выводящей в консоль браузера данные, на которые накладывается шаблон.Другим важным параметром является объём данных, которые грузит пользователь. В yate есть возможность разбивать шаблоны на модули и указывать зависимости между ними. Таким образом, модули можно подгружать по мере необходимости, а при трансформации указывать, какой именно модуль нужен, чтобы сгенерировать тот или иной кусок HTML.
![image](https://habrastorage.org/getpro/habr/post_images/89f/bb9/38f/89fbb938f6e1b902cd44b119c12827e1.png)
Также в yate легко добавлять свои функции, например, для работы со строками или датами. Для этого достаточно задекларировать функцию, реализовать её на JavaScript и использовать:
![image](https://habrastorage.org/getpro/habr/post_images/1be/848/424/1be848424c1d607f594e5c108430f5ae.png)
Результат
Яндекс.Почта была переведена на новый шаблонизатор за полтора месяца.
Некоторые сервисы, используемые в Почте, еще не переехали на JSON, поэтому для них мы используем E4X процессор XML2JSON. Так как произошли и серьёзные архитектурные перестановки, то Диск, который пока остался на XSL/XML, теперь открывается только с перезагрузкой страницы. Но мы добились своей цели. Измерения показали, что мы не только не «просели» во времени загрузки Почты:
![image](https://habrastorage.org/getpro/habr/post_images/1ed/5e1/168/1ed5e1168e2a1ea540f6a89f26ea9f25.png)
Но и существенно уменьшили время переходов по страницам внутри Почты:
![image](https://habrastorage.org/getpro/habr/post_images/7ec/c30/8d3/7ecc308d3588a67a5477afa11098c6c6.png)
Также мы получили гибкое, расширяемое и контролируемое нами решение, которое намерены развивать и совершенствовать.
DIY
Мы обязательно напишем, как использовать yate в ваших проектах. А если вы хотите попробовать yate уже сейчас, вам достаточно сделать
npm install yate
. В качестве документации можно использовать презентацию или вики про синтаксис и jpath. Также вам может понадобиться аналог XPath для JSON (jpath или no.path) и подсветка синтаксиса для vim или Sublime Text. Если у вас уже есть XSL-шаблоны, то вы сможете оценить, как будет выглядеть yate с помощью xsl2yate.