![](https://habrastorage.org/files/4e4/014/3e1/4e40143e18e04fe6a48a69fde278318a.png)
Вариантов было несколько:
- Meteor
- Angular
- Ember
Но остаться должен только один. Meteor предлагает интересную концепцию – общий код клиента и сервера, но он пока сыроват и мне не хотелось оставлять прекрасный язык Ruby. Поэтому Метеор отпал. Так как Ember был похож на Rails (магия, convention over configuration), то был выбран именно он. Помимо этого, очень симпатично выглядел шаблонизатор Handlebars по сравнению с директивами Angular.
Выбор сделан. Вот тут и начались проблемы.
Руководство написан очень неплохо, все делается хорошо, но вот когда начинаешь что-то делать сам, возникают постоянные вопросы. Основной проблемой у меня было то, что я не видел картину в целом, не понимал архитектуру. Статей на эту тему мало, а те что есть, рассказывают про самые базовые понятия, поэтому и появилась данная заметка.
Ember называют MVC фреймворком, поэтому я ожидал увидеть что-то похожее на Ruby on Rails и классический MVC. Но не тут то было! Помимо модели, представления и контроллера (которые делают совсем другие вещи чем на сервере), здесь было много разных вещей: компоненты, маршруты, адаптеры, сериализаторы, шаблоны, хранилище.
Порог входа высок и было довольно сложно собрать в голове все это воедино, понять, что с чем взаимодействует. Именно поэтому я хочу поделиться с вами небольшой схемой Ember, она описывает работу компонентов, их взаимодействие. Надеюсь она поможет вам с пониманием происходящего в приложении, его изучением и более быстрым и простым вхождением, чем это было у меня.
Жизненный путь запроса
![image](https://habrastorage.org/getpro/habr/post_images/65d/a86/491/65da86491f185030954e1d417cb4803a.png)
Рассмотрим схему более детально.
Точка входа
Приложение у нас одностраничное, так что точка входа у нас одна — index.html. Все переходы будут делаться с помощью якоря или history api. Все пути будут рабочими, то есть вы можете легко добавить нужную страницу в закладки и контент будет доступен по ней.
Маршрутизатор
Первым делом у нас работает Router. Именно он выбирает что делать дальше в зависимости от адреса и передает управление указанному в нем маршруту.
Маршрут
Route обрабатывает входящие данные, например параметры url, и обращается к модели или моделям. Он является связующим звеном между данными(Model) и их обработчиком (Controller).
Модель
Модели – это наши сущности, например в блоге – пост, пользователь, комментарий. Здесь уже используется не чистый Ember, а его дополнение – Data.
Для того чтобы получить указанные объекты есть 2 варианта:
- Получить их с помощью API.
- Получить из локального хранилища, в которые данные были добавлены при прошлом запросе в API.
При работе с хранилищем все просто – данные там лежат уже в виде объектов и при запросе достаются оттуда, а вот для работы с API используются еще 2 сущности: адаптеры и сериализаторы.
- Адаптеры задают правила работы с API, например получить все посты – GET /posts, а обновить пост – PUT /posts/1.
- Сериализаторы разбирают json-ответ сервера и устанавливают формат json-запроса.
Контроллер
Когда мы получили данные, мы можем приступить к их обработке. Именно в контроллере описываются вычисляемые свойства (computed properties). Контроллеры бывают нескольких видов:
- Controller – обычный контроллер, например для статичных страниц.
- ObjectController – для представления одного объекта.
- ArrayController – для представления массива объектов, может иметь еще вложенный ObjectController для каждого объекта(например для вычисляемых свойств каждого объекта) [1]
Представление
После этого необходимо отрисовать наши данные. Тут нам приходят на помощь шаблоны, представления и компоненты. Давайте сначала поговорим о шаблонах – участках html кода в который вставляются наши данные. Они могут содержать партиалы, компоненты и представления.
Теперь поговорим о представлениях и компонентах. Компоненты являются наследниками представлений, поэтому и то, и второе – это повторяемые участки кода. В связи с скорым переходом к версии 2.0 [2] нам советуют использовать лишь компоненты.
Components – целостные участки кода, отвечающие за одну функцию и которые будут использоваться в разных местах. Возьмем пример из жизни: мне необходимо было чтобы длинный текст автоматически сворачивался и появлялась кнопка «Развернуть». Именно для этого я использовал компоненты.
Партиалы – это те же самые шаблоны, которые вставляются в другие шаблоны, к ним все это относится точно так же.
Действия/события
Теперь необходимо немного рассказать про действия и action bubbling – цепочку действий.
Действия – то что происходит при определенных событиях(нажатию на элемент, отправку формы). Они описываются в контроллерах, маршрутах, представлениях, компонентах.
Рассмотрим небольшой участок кода:
// index.hbs
<h1 {{action 'doSomething'}}>{{post.title}}</h1>
// index-controller.js
App.IndexController = Ember.Controller.extend({
actions: {
doSomething: function() {
console.log('Вы только что нажали на заголовок')
}
}
})
При клике на заголовок это событие передастся в соответствующий контроллер и там обработается – в данном случае выведет надпись в консоль браузера.
Action Bubbling
Action bubbling – это передача события вверх по цепочке если не был найден обработчик в маршруте/контроллере.
Пусть у нас будет такие маршруты, контроллеры и представления:
// post-route.js
App.PostsRoute = Ember.Route.extend({
actions: {
doSomething: function() {
// 1
}
}
})
// posts-controller.js
App.PostsController = Ember.ArrayController.extend({
itemController: 'post'
actions: {
doSomething: function() {
// 2
}
}
})
// post-controller.js
App.PostController = Ember.ObjectController.extend({
actions: {
doSomething: function() {
// 1
}
}
})
// posts.hbs
{{#each post in controller}}
<h1 {{action 'doSomething'}}>{{post.title}}</h1>
{{/each}}
При клике на название поста выполнится самое ближайшие действие – т.е. в PostController, если его нету – перейдет на уровень выше, и так дальше.
Вот то же самое в виде схемы:
![image](https://habrastorage.org/files/35e/bef/abc/35ebefabc8e943f5ad65fc74f6c81a84.png)
Примерно так в общем чертах выглядит жизненный цикл одного запроса в приложении Ember и я надеюсь вам она поможет со понимаем архитектуры и стартом изучения этого замечательного фреймворка.
P.S.: Если это будет интересно, в следующей статье я расскажу про написание приложения на EmberJS, интеграцию с Ruby on Rails, дополнительными пакетами и Ember CLI.