1 Введение
В статье мы сравним три популярных MV* фреймворка для веб-разработки: AngularJS, Backbone и Ember. Выбор подходящего фреймворка для проекта кардинально влияет на вашу возможность выполнять задачи вовремя и поддерживать ваш код в будущем. Вам нужен надёжный, проверенный фреймворк, но вы не хотите, чтобы он вас ограничивал. Веб быстро развивается, и старые методики уходят в прошлое. Займёмся же подробным их сравнением.
2 Познакомьтесь с фреймворками
У всех рассматриваемых фреймворков есть общие черты: их код открыт, выпущен под лицензией MIT, и они решают задачу создания одностраничного приложения через шаблон проектирования MV*. У всех есть концепции видов, событий, моделей данных и путей.
AngularJS родился в 2009 как часть большего коммерческого продукта GetAngular. Вскоре после этого Миско Хевери, один из инженеров-основателей GetAngular, сумел воссоздать при помощи этого продукта веб-приложение, состоявшее из 17 тысяч строк кода и делавшееся в течение 6 месяцев, всего за 3 недели, и уложиться при этом в тысячу строк кода. В Google впечатлились таким фактом и стали спонсировать проект с открытым кодом AngularJS. Среди его возможностей – двустороннее связывание данных, инъекции зависимостей, простой для тестирования код и расширение возможностей HTML при помощи директив.
Backbone.js – легковесный MVC-фреймворк, родившийся в 2010. Популярность набрал в качестве альтернативы тяжёлым фреймворкам вроде ExtJS.
Ember родом из 2007 года. Он начинался как SproutCore MVC фреймворк, и сначала его разрабатывали SproutIt, затем – Apple. В 2011 году его форкнул Иехуда Кац, один из главных программистов в проектах jQuery и Ruby on Rails.
3 Сообщества
Сообщество – один из важных факторов для выбора фреймворка. Больше сообщества – больше ответов на вопросы, сторонних модулей, тьюториалов на YouTube… Я составил табличку, актуальную на апрель 2014 года. Angular явно выигрывает – это 6-й популярный проект на GitHub и вопросов по нему на StackOverflow больше, чем в сумме у Ember и Backbone:
Кроме текущих показателей можно при помощи Google Trends посмотреть на скорость роста популярности фреймворков:
4 Размеры фреймворка
Время загрузки страниц – вещь для успеха сайта критичная. Пользователи не отличаются терпением, поэтому необходимо стараться ускорять загрузку как можно сильнее. На это влияют два фактора – размер фреймворка и время, которое требуется ему на запуск.
Мы будем сравнивать минифицированные версии в архиве gzip. Но недостаточно сравнить размеры самих фреймворков. Например, Backbone.js, несмотря на малый размер, требует ещё Underscore.js (5kb) и jQuery (32kb) или Zepto (9.1kb).
5 Шаблоны
Angular и Ember включают движок шаблонов. А Backbone оставляет его на усмотрение разработчика. Лучший способ протестировать шаблоны – это взять пример кода. Мы возьмём пример форматирования списка в HTML.
5.1 AngularJS
У Angular шаблоны – это HTML со связывающими выражениями. Выражения окружены двойными фигурными скобками:
<ul>
<li ng-repeat="framework in frameworks" title="{{framework.description}}">
{{framework.name}}
</li>
</ul>
5.2 Backbone.js
Хотя Backbone можно интегрировать с несколькими движками шаблонов, по умолчанию используется Underscore. Но обработка шаблонов с его помощью довольно примитивна, и приходится добавлять код на JS:
<ul>
<% _.each(frameworks, function(framework) { %>
<li title="<%- framework.description %>">
<%- framework.name %>
</li>
<% }); %>
</ul>
5.3 Ember.js
Ember на сегодняшний день использует Handlebars – это расширение популярного движка Mustache. Сейчас разрабатывается новый вариант Handlebars по имени HTMLBars. Handlebars не понимает DOM – он просто работает со строками. HTMLBars будет понимать DOM.
<ul>
{{#each frameworks}}
<li {{bind-attr title=description}}>
{{name}}
</li>
{{/each}}
</ul>
6 AngularJS
6.1 Преимущества
Angular привнёс много новых концепций. Двустороннее связывание данных позволяет минимизировать код. Возьмём такой пример на jQuery:
$('#greet-form input.user-name').on('value', function() {
$('#greet-form div.user-name').text('Hello ' + this.val() + '!');
});
Благодаря двустороннему связыванию, такой код писать не придётся. Вы просто объявляете связку в шаблоне:
<input ng-model="user.name" type="text" />
Салют, {{user.name}}!
Обещания играют важную роль в angular. JS – язык однопоточный и событийный, поэтому много чего происходит в асинхронном режиме. Асинхронный код на JS быстро разрастается и превращается в спагетти из вложенных обратных вызовов. Его часто обзывают «Пирамидальный код» или «Ад с обратными вызовами».
У Angular не только самое большое сообщество, его поддерживает и рекламирует Google. Открытый код позволяет всем принимать участие в разработке фреймворка. Вот здесь находятся документы по дизайну Angular 2.0, и все могут знакомиться и комментировать их.
Angular разбивает приложение на блоки нескольких типов: контроллеры, директивы, фабрики, фильтры, сервисы и виды. Они, в свою очередь, разбиваются на модули. У всех блоков – своя роль. Виды занимаются UI, контроллеры – логикой интерфейса, сервисы общаются с бэкендом, директивы позволяют создавать компоненты и расширяют HTML.
«Angular написан с учётом тестируемости» – эта цитата из руководства по юнит-тестам говорит о многом. Действительно, Angular сильно заботится о разделении сущностей, изолировании юнитов и предоставляет мощные средства для работы со встроенными сервисами вроде $http и $timeout.
6.2 Недостатки
Angular часто критикуют за сложность API директив. Особенно запутывает разработчиков концепция трансклюзии, а кроме того есть такие вещи, как компиляция функций, пред- и пост- линкуемые функции, разные виды областей видимости и настройки директив.
Иерархия областей видимости использует прототипное наследование, которое сложно даётся для людей с опытом в Java и C#.
Angular Expressions широко используются в Видах. Этот язык довольно мощный, иногда даже чересчур. Он позволяет создавать сложную логику и проводить операции присваивания и различные подсчёты внутри шаблонов. Размещение логики в шаблонах усложняет тестирование. Рассмотрим следующий пример перегруженного вычислениями шаблона:
<button ng-click="(oldPassword && checkComplexity(newPassword) && oldPassword != newPassword) ? (changePassword(oldPassword, newPassword) && (oldPassword=(newPassword=''))) : (errorMessage='Введите пароль, соответствующий следующим требованиям: ' + passwordRequirements)">Жмите</button>
Во многих случаях легко ошибиться в имени директивы или функции, и тяжело найти эту ошибку.
Digest Cycle, обеспечивающий магию «грязных проверок» также часто удивляет разработчиков. Легко забыть вызвать $digest(), работая в контексте, отличном от Angular. Нужно заботиться о том, чтобы случайно не сделать бесконечные digest-циклы. На страницах с обилием интерактива Angular начинает тормозить. Не стоит использовать более 2000 связок на одной странице.
7 Backbone.js
7.1 Преимущества
Backbone – легковесный и не занимает много памяти. Кривая обучения линейная, и у него есть очень мало концепций для понимания (модели/коллекции, виды, пути). Отличная документация, а код простой. Вы даже можете пройтись по всему коду фреймворка, который хорошо документирован, и ознакомиться с ним в течение часа.
На его основе можно строить свои фреймворки. Примеры готовых: Backbone UI, Chaplin, Geppetto, Marionette, LayoutManager, Thorax, Vertebrae. В случае Angular и Ember вам приходится жить с тем, что для вас приготовили разработчики. В Angular 2.0 обещают это исправить, но до этого ещё надо дожить.
7.2 Недостатки
Backbone не предоставляет структуры. Это всего лишь набор простых инструментов для создания структуры, и вам нужно заполнить много пустых мест. Конечно, многие из этих мест заполняются сторонними плагинами – но это значит, что вам нужно принять много решений при их выборе. К примеру, вложенные модели можно сделать при помощи Backbone.DocumentModel, BackBone.NestedTypes, Backbone.Schema, Backbone-Nested, backbone-nestify и так далее. Выбор лучшего решения занимает время – а суть фреймворка в экономии вашего времени.
Нет поддержки двусторонней связанности данных, то есть вам придётся писать много вспомогательного кода для обновления вида при изменениях модели, и для обновления модели при изменениях вида.
Виды в Backbone напрямую манипулируют DOM, поэтому их сложно тестировать и сложнее повторно использовать.
8 Ember.js
8.1 Преимущества
Ember.js работает по принципу «соглашения вместо настроек». Ember не требует написания вспомогательного кода, он может сам догадаться до многих вещей, например автоматического определения имени пути и контроллера при определении ресурса. Он даже умеет автоматически создавать контроллер для ресурса, если вы его не определите.
Он включает хороший обработчик путей и опциональный слой для работы с данными под названием ember data. В отличие от двух других фреймворков, у Ember сразу есть модуль для работы с данными, который хорошо интегрируется с бэкендом Ruby-on-Rails или любым API с RESTful JSON.
При разработке Ember внимание уделялось быстродействию. Ваше приложение скорее всего будет грузиться и работать быстрее.
8.2 Недостатки
API бурно развивался, поэтому содержит устаревший контент и примеры, которые уже не работают. Взгляните на Ember Data Changelog, и вы поймёте, что я имею в виду. Многие ответы на вопросы на StackOverflow уже неактуальны.
Handlebars загрязняют DOM множеством тегов
<script>
, что не только усложняет HTML, но и может поломать CSS или интеграцию с другими фреймворками вроде jQuery UI Sortable.9 Итоги
Мы рассмотрели преимущества и недостатки фреймворков. Целостный подход Ember к реализации MVC понравится тем разработчикам, которые исповедовали его в Ruby, Python, Java, C# и других ООП-языках. Он также подходит для создания быстро работающих приложений и избавляет вас от написания лишнего кода.
Backbone выступает за минимализм. Он мелкий, быстрый и простой в обучении, и обеспечивает вам минимум необходимых инструментов для работы.
Angular инновационно подходит к расширению возможностей HTML, он понравится веб-разработчикам. У него большое сообщество и поддержка со стороны Google, он будет расти и развиваться, и он хорошо подходит как для быстрого прототипирования, так и для объёмных проектов.
Комментарии (21)
Igogo2012
02.06.2015 09:39+9По моему подобных статей на хабре с десяток, как-то не актуально уже такое видеть здесь в очередной раз…
IonDen
02.06.2015 11:38+1React + Flux передают привет всем этим технологиям.
voidnugget
03.06.2015 07:13+1Где-то десяток Flux'ов на самом деле, и как-то не один пока не приглянулся…
JSwarrior
02.06.2015 11:53JS – язык однопоточный
А как же Web Workers?Nadoedalo
02.06.2015 14:20Проблема в том что Web Workers используется только в очень тормозных задачах — например отсортировать массив из 10к элементов в фоне что бы у человека не тормозил сам браузер. Так он очень редко используется в повседневных задачах — нет смысла гемороиться с многопоточностью пока хватает скорости работы, чего в большинстве случаев достаточно. Либо где-то что-то используется неоптимально.
Примеры — сложные вычисления в рекурсии, некоторые варианты с графикой(когда нужно много чего посчитать как можно быстрее) и т.п вещи.
Deamon87
03.06.2015 07:51+1А вы посмотрите на модель программирования, которая используется в Web Workers. Эти самые воркеры не способны использовать переменные из основного потока. Вся коммуникация основного потока строится по типу — отдали объект-параметры, получили объект результат в callback`е. Причем callback исполняется в основном потоке.
Благодаря такой модели, парадигма программирования на js не меняется. Не нужно вводить никаких примитивов синхронизации и прочих радостей, присущих многопоточным языкам.
Потому смело можно говорить, что js так и остался языком с одним потоком
Nadoedalo
02.06.2015 14:17+3Backbone
1) Нет поддержки двусторонней связанности данных, то есть вам придётся писать много вспомогательного кода для обновления вида при изменениях модели, и для обновления модели при изменениях вида.
2) Виды в Backbone напрямую манипулируют DOM, поэтому их сложно тестировать и сложнее повторно использовать.
1) this.model.on('change', this.render, this); Вуаля — при изменении модели будет рендерится заново вьюха(при условии использования шаблонов), примерно с таким же успехом как и в Angular. С обратной связью(вью->модель) немного сложнее, но обычно это всё дело привязано к кнопке или действию. Под кнопку всёравно писать код что там что там ибо нужно сохранять на сервер в большинстве случаев. Действия могут обрабатываться по правилам и, соотвественно, можно не писать под каждое поле а обойтись универсальной функцией, где имя поля ввода будет действительно что-то значить.
2) Они не напрямую манипулируют DOM, они используют ссылку на кусок DOM'а, и их легко использовать повторно — достаточно сделать extend и внести минимальные правки(например изменить название загружаемого шаблона, у вас ведь он в свойствах вьюхи находиться?) + добавить/изменить/заекстендить ивенты. В итоге единожды написанный код у меня используется с минимальными правками в 2-3 представлениях.
И почему в жирнючие минуса Angular'а не внесли его отстойный вариант «улучшения» HTML? Такое чувство что опять вернулись во времена onclick прямо на элементах. Ужасно сложно дебажить логику которая скрыта за шаблонизатором.
Про недостатки Embera и его script. Ребятки а вы что, requireJS не используете? Он тоже «засоряет». Не вижу проблем.
Backbone предоставляет не минимум — Backbone предоставляет достаточное количество инструментов что бы построить с помощью них что угодно, включая свои инструменты. Если вам нужна скорость разработки — взгляните на фреймворки построенные на библиотеке Backbone — например Чаплин или Марионетку.Blumfontein
09.06.2015 07:41+1>> И почему в жирнючие минуса Angular'а не внесли его отстойный вариант «улучшения» HTML?
Потому что для кого-то это не минус?Nadoedalo
09.06.2015 13:38Ну не спорю, конечно для разработчиков времён onclick на элементах это может быть и не минусом, но остальной мир двинулся вперёд — и весь этот ng-мусор никакой полезной нагрузки для парсера и рендера DOM'а по HTML не несёт. По факту angular сделал браузер-в-браузере — сначала сам смотрит, потом браузеру отдаёт. Причём на любой чих и без альтенратив — он просто так работает. Вам не кажется этот способ — костыльным?
alist
02.06.2015 23:11+1Оригинальная статья очень старая, и многие пункты вообще неприменимы сегодня.
Например, аддонов у Эмбера уже больше 1000, HTMLBars уже давно в релизе, а в бете его дальнейшее развитие — Glimmer. Наверняка по другим фреймворкам ситуация похожая.
Holms
03.06.2015 03:34+2как-то странно что Knockout не включили, он намного ближе к Angular чем остальные два.
lolmaus
03.06.2015 09:07+1Какого года статья? По Ember информация совершенно неактульная. Количество аддонов перевалило за тысячу, и Ember давно не добавляет script-элементы в DOM.
Некоторое время назад я сравнивал Ember с Angular и Backbone, описал личный опыт: habrahabr.ru/post/255769/#comment_8376441
xxicb
03.06.2015 09:36Единственная жесткая зависимость у Backbone это Underscore (в статье добавили jQuery/Zepto), в связи с чем он самый легковесный
bo883
03.06.2015 09:56+1Прочел, и сложилось впечатление — angular красавчик все остальное так себе, надоело. Надеялся что что то актуальное, полезное… но очередная статья восхваления.
Зы: Ожидал от статьи типа: Использовали в проекте все 3 фремворка/библиотеки — вот такие косяки, вот такие преимуществ…
fr33z3
08.06.2015 18:56Handlebars загрязняют DOM множеством тегов
Помоему не правильно либо переведено, либо сама статья написана корява. Создается впечатление, что handlebars генерирует кучу тегов script. Но это не так. Для имплементации темплейтов необходимы теги, в которых пишутся темплейты. Но это к слову не достаточное условие. Можно вполне себе прекомпилировать темплейты в полноценный javascript на этапе компиляции остального javascript'а. Все равно вероятнее всего кто-то использует coffescript, да даже просто конкатенация скриптов. А прекомпиленным темплейтам не нужно лишний раз компилиться в рантайме. Так что этот минус надуманный, а вот реальный минус, так это действительно гайды, отстающие от билдов. Но вообще всем советую даже ради интереса попробовать Эмбер, очень простой в освоении и красивый фреймворк.
andrew-r
Бэкбон — это не фреймворк. Понимаю, что это следует сказать автору статьи, но зачем уж делать переводы таких статей?
auine
Ох, как хорошо встретить человека который это понимает и уже отпостил за тебя :)
К слову:
Есть такой сайтик — backplug.io на котором есть куча плагинов в том числе включащих поддержку two-way биндинга. Бекбон распределенный инструмент, как и нод. Он из коробки не предоставляет вам больше чем несколько логических структур. Я не считаю недостатком, что у него нет структуры. Это плюс, причем большой. Во многих кейсах надо минимальная абстракция и полный котроль на ДОМом. Но хотя есть марионет, который даст вам то, что нужно в виде фреймворка.
Что косаемо тестирования и компонентов. Используете require и модули будут вам компонентами. С тестированием тоже проблем не наблюдается.