JsRender: Новое поколение jQuery Templates

    Буквально пару месяцев назад, мы начали переписывать весьма крупный сайт, с момента прошлого крупного релиза прошёл не один год, конечно, сайт дорабатывался, правились баги и в итоге в настоящее время создаётся новая версия. В ней будет активно использоваться AJAX, поэтому весьма остро стоял вопрос с генерацией контента на клиенте, полученного в формате JSON. Прошлые шаблоны были собственной разработки, так как на то время вариантов было не так много, которые по разным причинам не подходили, базировались наши шаблоны на jquery, с помощью атрибутов происходило заполнение.

    Прежде всего было решено провести тест, при генерации списка из 1500 элементов было получено превосходство в 20 раз, похожие результаты показывает сравнение с jQuery Template (страница с тестами).

    На JsRender я вышел довольно просто. Зайдя на страницу jQuery Templates, я прочитал, что команда jQuery решила не выводить данный плагин из беты, они своё слово сдержали и уже 6 месяцев не было никаких обновлений. На этой же странице указана ссылка на блог разработчика JsRender.

    JsRender оптимизирован на высокую производительность, используются обычные строки, без взаимодействия с DOM или jQuery, что вполне логично добавляют ему производительности, так как во многих статьях о jQuery, можно встретить советы, не использовать jQuery, например, для получения id (без конструкций вида: $(this).attr('id')) и для генерации разных списков использовать только строки, после чего вставлять их в DOM одним махом.

    Рассмотрим пример с сайта:
    <html>
    <body>
    <script id="movieTemplate" type="text/x-jsrender">
    	<div>
    		{{:#index+1}}: <b>{{>name}}</b> ({{>releaseYear}})
    	</div>
    </script>
    
    <div id="movieList"></div>
    
    <script type="text/javascript">
    
    	var movies = [
    		{ name: "The Red Violin", releaseYear: "1998" },
    		{ name: "Eyes Wide Shut", releaseYear: "1999" },
    		{ name: "The Inheritance", releaseYear: "1976" }
    	];
    
    	$( "#movieList" ).html(
    		$( "#movieTemplate" ).render( movies )
    	);
    
    </script>
    </body>
    </html>
    


    В данном примере мы имеем:

    1. Шаблон (id=«movieTemplate»), неизвестный тип контента не будет обрабатываться браузером, поэтому он его рассматривает просто как текст.
    {{:#index+1}} — на вход мы подаем массив объектов, с помощью решетки мы можем получить индекс, так как он начинается с нуля, то прибавляем единицу
    {{>name}} — обращение к свойствам объекта, треугольная скобка говорит о том, что мы будем кодировать строку, т.е. будут видны теги.
    2. Контейнер, куда будет вставлен контент (id=«movieList»).
    3. Сам скрипт, где с помощью jQuery находится шаблон, происходит его заполнение с помощью render и данные вставляются в контейнер.

    После чего мы увидим такой результат:


    Основы синтаксиса в таблицах











    Пользовательские теги, вспомогательные метода и конвертеры







    Это лишь часть возможностей, в конце статьи, я приведу исчерпывающий список ссылок.

    Отладка



    Возьмём, например этот пример Helper functions. Какие-то вещи вам могут показаться не очевидными. Для своих целей я писал довольно много конвертеров и вспомогательных методов, стоит поставить точку остановки и пройтись по свойствам, многое прояснится. Я использовал Firebug, вот пример, где можно посмотреть, что содержит ссылка на объект this, которая используется в данном контексте:



    Важно



    На сайте проекта JsRender написано, что она близка к бете, разработчик обещал официальную бету в апреле или мае 2012 года на данной странице, но пока её ещё нет. Возможны изменения API, добавление новых фич и т.д. По указанной ссылке также можно задавать вопросы разработчику, судя по комментариям он довольно оперативно реагирует.

    Ссылки



    Основы JsRender (слайды): JsRender Fundamentals: Templating for HTML5 Applications
    Официальные примеры: JsRender: Demos
    Статья из двух частей: Using JsRender with JavaScript and HTML и Advanced JsRender Templating Features
    Поделиться публикацией
    Комментарии 47
      +1
      Шустрее doT пока всё-равно ничего не придумали.
        0
        Насколько я вижу, то сейчас там загружена в тестах не оптимизированная версия JsRender?

        После этого инцидента:
        Revision 400: published by [jsRender won through incorrect output — removed] on 12th April 2012

        А во втором тесте у меня победу одержал: Kendo UI Templates (No «with» block)
        0
        форк DustJS от LinkedIn linkedin.github.com/dustjs/
          0
          Не нашёт сравнительных тестов…
          0
          Ага. Единственное, для поиска ошибок в шаблонах ничего не сделано.
            0
            Ну, строку, конечно, не пишет, но ошибка вполне себе нормально видна в консоли и по её тексту можно догадаться, что именно не так.
          +1
          Хорошо бы ещё написать про JsViews, вместе с которым JsRender становится действительно вкусной вещью.
            0
            С JsViews ещё не работал, дальше примеров дело не дошло, а писать о том, с чем пока не имел реальной практики я посчитал лишним. Для тех кому интересно, что такое JsViews, могут зайти на сайт и посмотреть примеры, учитывая, что JsViews базируется на основе JsRender, знакомство я бы начал с последнего.
            0
            > во многих статьях о jQuery, можно встретить советы, не использовать jQuery, например, для получения id (без конструкций вида: $(this).attr('id'))

            Не совсем так, при генерации для установки id не следует использовать $(this).attr('id', 'foo')

            > и для генерации разных списков использовать только строки, после чего вставлять их в DOM одним махом.

            Именно так. Сначала собрать всю разметку по максимуму с атрибутами, классами и идентификаторами, только потом вставить её в DOM целиком.

            А взаимодействовать с DOM всё равно придётся. Вопрос в том, сколько раз и сколько водопапов событий будет при этом спущено.
              0
              Ответил ниже.
                0
                > Не совсем так, при генерации для установки id не следует использовать $(this).attr('id', 'foo')

                Понятно, что $(this, { id: 'foo' }) проще, но в чём причина совета «не следует»?
                  0
                  Мы всё ещё о генерации говорим?

                  Не следует сначала генерировать, а потом раздавать атрибуты.
                    0
                    А как следует делать? Сразу в html собирать строку и передавать в $()?
                      0
                      Именно так, да.
                0
                Вы привели пример установки, а я говорил о получении.

                Вместо:
                $('a').each(function(){
                    console.log($(this).attr('id'));
                });
                


                Использовать:
                $('a').each(function(){
                    console.log(this.id);
                });
                
                  –7
                  вы придумали Mustache.js
                    +4
                    я придумал? я лишь рассказал о данном проекте, никакого отношения к разработке JsRender я не имею. Синтаксис с Mustache.js похож, но обозначает он разные вещи, главное что пересекается — это {{ }}.
                    0
                    Было бы полезно сравнить результаты этого движка с остальными на jsPerf.

                    Вот я когда-то сравнивал свой KiTE с другими:
                    jsperf.com/dom-vs-innerhtml-based-templating/99

                    Кстати про KiTE. У меня используется базовый mustache синтаксис расширенный if секциями.
                    Template компилируется в своеобразный bytecode — массив из строк и функций. Получается в 25 раз быстрее чем mustache. Ну и это все в 180 LOC поместилось. Надо бы глянуть во что их движок вылился в результате.
                      0
                      А есть более подробные цифры?
                      Ну например: «Ваши зубы белее на 20%», а «был цвет RAL1013, а стал RAL9003»
                        0
                        Конечно есть, на 1500 элементах тесты показали:
                        460 ms +- 10% — наши шаблоны
                        21 ms +- 10% — JsRender

                        600 элементов: 190 ms и 7 ms соответственно.

                        А тесты с jQuery Template есть во втором абзаце.
                          0
                          Ожидаемо.
                          Я недавно получил аналогичные результаты, только делал это вручную:
                          habrahabr.ru/post/147252/
                          Было
                          Views: 490.9ms | ActiveRecord: 14.4ms
                          Стало
                          Views: 12.9ms | ActiveRecord: 17.1ms
                        +3
                        Помоему сейчас столько шаблонизаторов развелось, что обсуждать преимущества одного над другим вообще смысла не имеет, мерится производительностью тоже (обычно грамотный шаблонизатор быстро работает а +- пара милисекунд не делают погоды)
                        Я даже больше скажу шаблонизаторы особо никому не нужны, обычно когда люди выбирают шаблонизатор — это знаит что на сайте мало js.
                        Если на сайте много js то люди уже выбирают средство для его структурирования, хороший фреймворк который организует код: будь то backbone или sproutcore или qooxdoo. Ну и как водится подобные рещения уже имеют свой шаблонизатор.
                        Так что дам совет тем кто выбирает шаблонизатор js:
                        1) У вам видимо небольшой сайт и не много js, 90% шаблонизаторов даже не покажут каких-либо задержек, бери любой который под рукой
                        2) У вас видимо реально большое приложение, где на основе тестов вы поняли что используемый шаблонизатор стал узким местом, тут мои советы излишни, вы сами знаете куда копать.

                        Я лично в последних проектах работал с backbone и соотвествено с шаблонизатором от underscore, тормозов не заметил, синтаксис приятен, что более нравится так там не надо заново учить новые операторы типо
                        {{for cast}}, зачем?? зачем этот синтаксис в шаблонизаторе, уже ведь есть js! поэтому в шаблонизаторе от undescore собственно три конструкции:
                        1. <%= … %> вывести значение<% … %> произвольный js<%- … %> вывести с экранированием тегов html
                          Фактически ничего не запоминаем нового и в тоже время пишем нужную логику без проблем.

                          Я не рекламирую это шаблонизатор как лучший, просто маленький пример.
                          0
                          Тоже им пользуюсь, удобно.
                          К тому же есть возможность настроить синтаксис на свой вкус.
                            0
                            Да, я активно юзал эту возможность, шаблонизатор использует стандартные теги от jsp а у меня как раз нужна была обработка этих шаблонов как jsp перед выдачей, поменял <% %> на {{ }} :)
                          0
                          Интересно было бы почитать сравнение всего многообразия строковых JS шаблонок.

                          Сам использую micro templating Резига
                            0
                            А что там справнивать, я вот лично не собо понимаю, уточните
                              0
                              Есть ли какая-то разница между ними )
                                +1
                                Не поверите!
                                1) библиотека лежащая в основе (jq template логично предположить без jq работать не будут, как и underscore)
                                2) Синтаксис
                                3)Скорость

                                Если будите выбирать то поступаем так:
                                1) Смотрим на то какая библиотека js используется в нашем проекте
                                2) Смотрим какие для этой библиотеки есть шаблонизаторы, выбираем самый приятный по синтаксису и функциям, по мне чем проще тем лучше, изучать дебри синтаксиса шаблона совсем не охота

                                Собственно все! На производительность смотреть только в том случа если они дает о себе знать ибо обычно в 97% это 5-10 шаблонов который выводят мелочь и их быстродействие ниоем образом не мешает юзеру. Вот когда вам в секунду 50 шаблонов рендерить придется тогда и задуматься стоит. А до этого ставьте на первое место удобство разработки и поддержки
                                  0
                                  1) библиотека лежащая в основе (jq template логично предположить без jq работать не будут, как и underscore)
                                  в данном случае предположение является ложным, вот пример без зависимостей: JsRender without jQuery
                                    +2
                                    О чем предположение? Вы наверное плохо читали. я имелл виду что выбор надо основывать учитывая библиотеку лежащую в основе приложения.
                                    Используя бекбон у меня уже есть undersсore template зачем мне подключать еще один? Используя dojo у вас там тоже есть нативный шаблонизатор от dojo, у sproutcore также есть свой шаблонизатор, так зачем подключать в проект еще один?
                                    Если нет серьузной причины используйте тот шаблонизатор что уже есть, вот когда он объективно не будет устраивать стоит думать о замене
                                      0
                                      сорри, не так понял смысл коммента
                                    0
                                    А зачем подписываться на библиотеко-зависимую шаблонку?
                                      0
                                      Вы тоже коментарии не читаете? Или вы любите пложить множество непонятных библиотек чтобы потом весейлей с ними жилось?
                                      Перечитайте внимателней оба мои коментария выше.
                                        0
                                        Кладешь шаблонку без зависимостей, в чем проблема?

                                        Цель шаблонки как я её понимаю, передать нечто и получить строку готового кода, тут не нужно, с моей точки зрения никаких либ.
                                          –1
                                          Проблема в том что если функционал создания щаблонов уже заложен в библиотеку, а он заложен во многие фреймворки, подключать что-то сторонее как минимум глупо и в 99% случаем вы будити идиотом сделав это.
                                          А оставшийся 1% я ждумаю вам не встретится никогда.
                                            0
                                            Ну вот я пользуюсь jQuery, в каком месте там встроенный шаблонизатор?
                                              0
                                              Уважаемый, вы совсем дурак? Читайте мои коментарии лучше. Вы не удосужились!
                                              А речь шла о том, что если в вашем фреймворке уже есть возможность работы с шаблонами, то надо в первую очередь использовать имено её, а не подключать еще одну не понятную библиотеку.

                                              И поверьте на одной jQuery жизнь не кончается.
                                                0
                                                Вы не ответили на вопрос.
                                                  0
                                                  Простите но видимо вам таки не понять. Успокойтесь и делайте как знаете.
                              +1
                              Шаманство всё это. Плагин для jQuery без jQuery, под который нужно учить отдельный синтаксис.
                              Лучше Knockout-а вряд ли что-то можно придумать.
                                0
                                  0
                                  я бы на их месте использовал бы html5 атрибут data все таки не зра его вводят, вместо своего ng
                                    0
                                    Ну, там есть такая возможность: data-ng- вместо ng-

                                    Но сути это не меняет — Нокаут лучше из-за самого сильного механизма observables. Я могу иметь наблюдаемое проперти, которое в свою очередь возвращает в качестве значений другой наблюдаемое проперти. Причем, все они могут быть зависимыми без указания мной явных цепочек зависимостей.

                                    image

                                    Но и для многих аспектов Нокаут предоставляет гораздо более удобное и лаконичное API. Те же кастомные байндинги в Нокауте делаются одной или двумя функциями, а в angular готового рецепта нет.
                                      0
                                      В AngularJS есть $scope.$watch("variable", function() { ... }) — в общем-то те-же observerables. А вот по поводу кастомных биндингов это вы совсем зря — есть же взиожность добавления кастомынх директив, даже на главной странице есть пример (про компоненты табов). Плюс за счет тех-же директив в ангуляре легко реализуются reusable-компоненты, с которыми в knockout была беда, насколько я понял (выбирал между двумя фреймворками).
                                  0
                                  Соглашусь. Многие теряют из виду тот факт, что темплейты Нокаута остаются валидным HTML-кодом, а значит их может править верстальщик или дизайнер без оглядки на синтаксис разработчиков. Тем более, с учетом того, что в большинстве случаев темплейты инлайнятся в текст страницы, а не прячутся в script тагах, темплейты верстальщик может править непосредственно по готовому живому HTML прямо из браузера.
                                  0

                                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                  Самое читаемое