0,0
рейтинг
30 декабря 2013 в 13:07

Разработка → От Backbone.js к Marionette.js

Привет, Хабр.

В этой статье пойдет речь о том, из чего состоит Marionette.js, и о возможности не писать свой велосипед.

Статья рассчитана в первую очередь на работавших с Backbone.js и/или Marionette.js.
Для вновь знакомящихся будет полезна первая, обзорная, часть и ссылки в конце статьи.

Для начала вспомним, что такое и из чего состоит Backbone.js
  1. Underscore.js — более 80 функций-помощников для удобной, кросс-браузерной работы с JavaScript.
  2. Backbone.Events — реализация базового класса событий плюс функции-помощники для связывания (bind) событий с объектами.
  3. Backbone.Model — модель данных с доступом до атрибутов ключ/значение. Имеет механизм загрузки/синхронизации с сервером.
  4. Backbone.Collection — коллекции моделей, приправленные 28 методами из Underscore.js. Как и модели, они имеют механизм загрузки/синхронизации с сервером.
  5. Backbone.Router и Backbone.history — базовые роутер и история страницы. Умеют детектировать совпавший путь и производить навигацию.
  6. Backbone.sync — реализация загрузки/синхронизации данных через REST с помошью jQuery.ajax.
  7. Backbone.View — представление. Из коробки не умеет ни рендерить себя, ни вставлять в DOM дерево.


Часть первая: Marionette.js


Представим, что мы пишем приложение на Backbone.js. В итоге мы получаем:

  • Базовое представление, которое реализует поддержку нужного нам шаблонизатора и нужные нам взаимосвязи с моделями;
  • Штуку, которая рендерит представление и вставляет его в DOM дерево;
  • Штуку, которая умеет отображать коллекции;
  • Штуку, которая отвечает за жизненный цикл представлений;
  • Расширение над роутером;
  • Штуку, которая запускает наше приложение;
  • Модульную систему, будь то папки с исходниками или одна из реализаций модулей JavaScript;
  • Скорее всего, что-либо ещё.

Под термином «штука» могут подразумеваться различные архитектурные реализации необходимых функций.

На прошедшей конференции BackboneConf неоднократно звучала идея, что Backbone.js — это основа (скелет) для написания фрэймворка. Причем основа достаточно хорошая.

Marionette.js является одной из библиотек, которая, используя всю гибкость Backbone.js, создаёт набросок архитектуры и реализует основу для написания больших веб-приложений.

Подробнее о том, из чего состоит Marionette.js (с картинками):


Backbone

  • Все, что нам предоставляет Backbone.js, мы можем использовать и в Marionette.js. Исключением являются представления Backbone.View, использовать их не имеет смысла, поскольку они не совместимы с механизмом Marionette.js добавления в DOM дерево.

Представления

  • Marionette.View — базовый класс для всех представлений Marionette.js. Реализует функции работы с DOM элементами и их событиями. Не предназначен для прямого использования.
  • Marionette.ItemView — представление для рендеринга данных на одном шаблоне. Данными могут выступать либо одна модель, либо одна коллекция. Если данные представлены коллекцией, то все её элементы будут переданы в шаблон массивом.
  • Marionette.CollectionView — представление пробегает по всем элементам коллекции и для каждой рендерит ItemView. Этот вид представлений не имеет своего шаблона, каждая из ItemView добавляется к “el” контейнеру CollectionView.
  • Marionette.CompositeView — тоже самое, что и CollectionView, плюс свой шаблон и модель данных для контейнера. Мы должны явно указать элемент-контейнер для добавления ItemView. Подходит, например, для отображения модели “условий поиска” и коллекции найденных записей.
  • Marionette.Layout — представление, которое отображает произвольный шаблон с данными как ItemView, плюс создаёт менеджер регионов, о котором пойдет речь ниже.

Управление представлениями

  • Backbone.BabySitter — контейнер для управления дочерними представлениями. Используется в CollectionView и CompositeView. Может быть использован c Backbone.View без Marionette.js.
  • Marionette.Region — управление регионом (областью) на странице. Простыми словами, регион — это объект, который содержит один html элемент и умеет вставлять в него html содержимое других представлений. В один момент времени регион отображает только одно представление. При добавлении нового представления в регион удаляется старое html содержимое и закрывается сам объект представления.
  • Marionette.RegionManager — управление группой регионов.
  • Marionette.Renderer — реализация рендеринга html из шаблона и данных. Используется во всех представлениях Marionette.js.
  • Marionette.TemplateCache — ленивая загрузка и кэш шаблонов underscore. Используется Marionette.Renderer. Для использования другого шаблонизатора рекомендуется переопределять именно Renderer и/или TemplateCache.

Модули и приложение

  • Marionette.Module — модули не предназначены для отслеживания зависимостей и никак не связаны со сборкой приложения, в отличие от AMD/CommonJS модулей. Модуль Marionette.js выполняет следующие важные для клиентского JavaScript задачи: запуск и остановка логической части приложения, элегантное пространство имен с возможностью описания одного модуля в нескольких файлах.
  • Marionette.Application — приложение можно описать как корневой модуль и базовый менеджер регионов. Имеет набор шин сообщений и механизм запуска всех модулей.
  • Marionette.Controller — дословный перевод: объект общего назначения для управления модулями, маршрутизаторами и представлениями. Реализует паттерн медиатор (посредник). Подробнее о контроллере/медиаторе — ниже.

Шины сообщений

  • Application.vent — глобальный экземпляр Backbone.Wreqr.EventAggregator. Реализует паттерн pub/sub. Подписчиков и публишеров может быть сколько угодно.
  • Application.commands — глобальный экземпляр Backbone.Wreqr.Commands. Подписаться на исполнение определённой команды можно только один раз. Если команда отправлена до создания «исполнителя», она будет исполнена при его создании.
  • Application.reqres — глобальный экземпляр Backbone.Wreqr.RequestResponse. Реализует паттерн request/response. Исполнять запрос может только один подписчик.

Остальное

  • Marionette.AppRouter — роутеры в Marionette.js должны быть тонкими, не должно быть “глобального” роутера всего. Задача роутера сводится к вызову нужного метода контроллера при совпадении пути, никакой бизнес логики.
  • Marionette.Callbacks — внутренний помощник вызова цепочки обратных вызовов.


Вывод: не пишем свой фрэймворк, используем Marionette.js.

Часть вторая: Контроллер/Медиатор


Настоятельно советую посмотреть все 9 часов скринкастов BackboneRails от Brian Mann. Материалы содержат огромное количество полезных штук, одна из которых является подробным описанием использования контроллера/медиатора.

Основная идея: жизненным циклом каждого представления или логически связанной группой представлений (Layout) управляет контроллер/медиатор.
Подробный пример: нам нужно отобразить список, пусть будет список «Яблок».

Мы создаём новый контроллер списка «Яблок». На контроллер, в свою очередь, ложатся задачи:

  1. Запросить необходимые данные (у провайдера данных через шину сообщений);
  2. Дожидаться загрузки данных, возможно, показывая спиннер загрузки;
  3. В случае списка «Яблок» отобразить CollectionView или CompositeView;
  4. Слушать события отображенного представления, например, клики по записи каждого яблока;
  5. При необходимости перенаправлять события в глобальную шину сообщений;
  6. При закрытии представления закрыть и самого себя;
  7. При закрытии самого себя закрыть и все свои подписки (bind) на события.

Подробнее о первом пункте

Логика того, “как” дожидаться данных, вынесенная из провайдера данных в контроллер/медиатор, позволяет нам в каждом конкретном случае обрабатывать это наиболее приемлемым для интерфейса пользователя способом. Например, в одном случае мы можем покрутить спиннером и после получения данных все отобразить, а в другом случае сначала отобразить пустое представление, а потом заполнить полученными данными.

Подробнее о пятом пункте

Казалось, можно было бы напрямую отправлять события представления в глобальную шину событий. Но прослойка в виде контроллера/медиатора позволяет нам использовать события представления в полной мере и проксировать события, необходимые только всему приложению. Пример: в случае яблок можно привести в пример кнопку “удалить яблоко” в этом списке и диалог подтверждения (“вы действительно хотите удалить это яблоко?”); только после двух этих событий, обработанных контроллером/медиатором, мы отправляем в глобальную шину сообщений, что такое яблоко удалено.

Вывод: контроллер/медиатор, реализующий паттерн медиатор (посредник), отлично подходит на роль связующего звена асинхронных данных, рендеринга представлений и действий пользователя.

Ссылки и материалы:


Друзья, про что из Marionette.js написать следующую статью?
65%
(89)
Модули Marionette.js
57%
(78)
Модуль как контейнер для «действия» из CRUD
53%
(73)
Сборка приложения на Marionette.js, AMD/CommonJS vs “cat *.js > app.js”
55%
(75)
Варианты использования шин событий: Commands, EventAggregator, RequestResponse
47%
(65)
Вольный перевод нескольких статей от Derick Bailey на тему использования роутеров

Проголосовало 137 человек. Воздержалось 79 человек.

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

Евгений Власенко @mahnunchik
карма
24,0
рейтинг 0,0
Пользователь
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (11)

  • 0
    Можно все пункты по порядку описать. Каждый из них в равной степени будет интересен.
  • 0
    Marionette — хороший фреймворк, но какие могут быть аргументы в его пользу, когда есть такие решения как AngularJS или EmberJS?
    • 0
      Я вообще не спец в фронтенде, но читал что тот-же EmberJS сильно навязывает стиль. Шаг влево, шаг вправо и начинается борьба с самим EmberJS.

      Angular хочу попробовать, да.
    • +3
      Ваш вопрос можно два раза повторить, просто поменяв MarionetteJS, AngularJS и EmberJS местами.
      Это просто еще один инструмент, в чем то он лучше, в чем то хуже, в чем то просто другой. Сравнений фреймворков в сети уже предостаточно, повторяться было бы излишне.
      • +1
        Полностью с вами согласен, а если и делать ещё одно сравнение, то не комментарием, а отдельным постом.

        И в тему библиотек с «встроенным» двунаправленным дата биндингом, недавно наткнулся на плагин для Backbone.js от New York Times для добавления этих возможностей там где это необходимо https://github.com/NYTimes/backbone.stickit
      • 0
        Хотел бы согласиться, сам не устаю повторять, что «Right Tool For The Right Job», но как всегда есть одно большое мохнатое «но».

        Много используя и то, и другое, и третье — все-таки, Backbone (с Marionette/Thorax/Chaplin) — старая школа, Ember — чертовски хорош своими соглашениями и достаточно похож на Backbone концептуально, а вот Angular — хотя и добавляет необходимость «ментального сдвига» — позволяет решать большинство тех же задач, используя втрое-вчетверо-всемеро меньшее количество кода.
  • 0
    не работает ссылка

    Примеры кода на каждый класс Marionette.js shustoff.su/blog/javascript/backbone-marionette
    • 0
      Не могу понять, почему ссылка вида shustov.su/blog/javascript/backbone-marionette

      Преобразуется к shustov.sublog
      • 0
        А нет, понял, автор блога редирект криво сделал =)

        Ссылка в статье была на shustoff.su

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