Фреймворки JavaScript. Как изучить их по-быстрому

http://www.funnyant.com/javascript-frameworks/
  • Перевод
Здравствуйте, коллеги.

Сегодня мы хотели затронуть такую многогранную и противоречивую тему, как фреймворки JavaScript. За последние несколько месяцев в издательстве неоднократно обсуждались перспективы издания книг и по Angular.js, и по Knockout.js, а книга по Backbone.js у нас выходила в прошлом году. Следующий материал призван помочь разобраться в сильных и слабых сторонах различных фреймворков JavaScript. Возможно, после изучения статьи читателю будет проще ответить на вопросы о том, так ли схожи эти фреймворки, и желает ли он дополнительно изучить какую-то из технологий, упомянутых в этом обзоре. Мы же попросим вас поделиться вашими соображениями о том, нужны ли новые книги по этим фреймворкам, если да — то по каким (высказываемся в комментариях, не стесняемся давать ссылки на книги).

Чтобы быстро изучать фреймворки JavaScript из разряда MV*, важно уметь представить любой фреймворк как ряд возможностей. Основные функциональные возможности MV*-приложения — это маршрутизация, привязка данных, шаблоны/представления, модели и хранилище данных. В данной публикации я собираюсь описать эти возможности и показать код реализации каждой из таких возможностей в двух или трех фреймворках. Для начала мы конкретно разберем, решение каких именно задач оптимизирует каждый из фреймворков, после чего, надеюсь, вы заметите во всех этих фреймворках больше сходств, чем различий. Оказывается, что в большинстве фреймворков активно заимствуются возможности, оправдавшие себя в других фреймворках.

Я предпочитаю видеть в людях сходства, а не различия — Исабель Альенде

Не утруждайте себя разбором каждой строки кода. Пока просто постарайтесь оценить, в чем схожи эти фреймворки, и какие проблемы они позволяют решать на проекте.

Маршрутизация

Как минимум, маршрутизация отображает ваши URL на действия, но иногда дело доходит до реализации полного паттерна «машины состояний» для управления переходами между состояниями в пределах представления.
Если вам когда-нибудь доводилось использовать маршрутизатор в серверном MVC-фреймворке, например, в Rails, CodeIgniter, CakePHP, ASP.NET MVC, Spring MVC, JSF, STRUTS, Grails и т.д., можете считать MV*-маршрутизаторы JavaScript аналогичными сущностями, но работающими на клиенте с JavaScript и прокладывающими маршруты к серверному коду, который может быть написан на PHP, Ruby, Java, C# и т.д.

Может возникнуть вопрос: а как все это будет работать в старых браузерах? Механизм работает по умолчанию, используя при этом в качестве маршрута всю информацию, которая расположена в URL после хэштега. Правда, если в HTML сконфигурирована поддержка пуш-состояний (в большинстве фреймворков это делается одной строкой кода), то URL без хэшей, совпадающие с маршрутами, будут перехватываться на клиенте и также выполнять код JavaScript.
Пуш-состояние НЕ ПОДДЕРЖИВАЕТСЯ по умолчанию, так как, несмотря на то, что URL, запрошенный непосредственно через закладку или пересланный в электронном сообщении, будет работать на компьютере конечного пользователя, поисковые роботы не слишком хорошо приспособлены к работе с JavaScript. То есть, робот может не выполнить код JavaScript, поэтому, не сможет просмотреть истинное содержимое страницы.

Решение, обычно предлагаемое в таких случаях – запустить на сервере PhantomJS или другой легковесный браузер, заставить его загружать страницы и JavaScript, а затем возвращать сгенерированную разметку вместе с JavaScript. Чтобы настроить этот механизм, нужно потрудиться, поэтому он задается по умолчанию для URL с хэштегами, поддерживаемых во всех браузерах.

Довольно объяснений, переходим к коду.

Пример с Backbone

Вот простой пример маршрутизации в Backbone.js

var HomeView = Backbone.View.extend({
      template: '<h1>Home</h1>',
      initialize: function () {
          this.render();
      },
      render: function () {
          this.$el.html(this.template);
      }
  });
  

var AboutView = Backbone.View.extend({
      template: '<h1>About</h1>',
      initialize: function () {
          this.render();
      },
      render: function () {
          this.$el.html(this.template);
      }
  });
  
  var AppRouter = Backbone.Router.extend({
      routes: {          
          '': 'homeRoute',
          'home': 'homeRoute',
          'about': 'aboutRoute',          
      },
      homeRoute: function () {
          var homeView = new HomeView();          
          $("#content").html(homeView.el);
      },
      aboutRoute: function () {
          var aboutView = new AboutView();          
          $("#content").html(aboutView.el);
      }
  });

  var appRouter = new AppRouter();
  Backbone.history.start();


В частности, обратите внимание на объект AppRouter. Маршруты отображаются на функции. Функции просто создают объект представления, управляющий фрагментом модели DOM, и добавляют его на страницу, как только URL изменится. Функция Backbone.history.start() приказывает Backbone начать слушать изменения URL.

Пример с AngularJS

Вот простой пример маршрутизации в AngularJS.

var routingExample = angular.module('FunnyAnt.Examples.Routing', []);
routingExample.controller('HomeController', function ($scope) {});
routingExample.controller('AboutController', function ($scope) {});

routingExample.config(function ($routeProvider) {
    $routeProvider.
    when('/home', {
        templateUrl: 'embedded.home.html',
        controller: 'HomeController'
    }).
    when('/about', {
        templateUrl: 'embedded.about.html',
        controller: 'AboutController'
    }).
    otherwise({
        redirectTo: '/home'
    });
});


Пример с AngularJS очень напоминает Backbone, за тем исключением, что маршруты отображаются на классы templateUrl и контроллеров (в таком контексте контроллеры подобны представлениям Backbone).
Пример с Ember

Ниже приведен простой пример маршрутизации в Ember.

App.Router.map(function() {
    // первый параметр относится к шаблону
    this.route('home', { path: '/' });
    this.route('about');
});


Опять же, пример очень похож на предыдущие, за тем исключением, что в Ember.js первым параметром «ресурсного» объекта маршрутизатора является имя routeName, а вторым — URL. На первых порах такой порядок следования меня запутал, пока кто-то не подсказал, что параметр пути необязателен и зачастую может устанавливаться по соглашению, как в случае со страницей about из этого примера. Кроме того, для запуска этого простого примера маршрутизации нужны шаблоны, но я остановлюсь на них только в конце статьи. Пока достаточно знать, что шаблоны помещаются в элементе {{outlet}}. Следует отметить, что маршрутизатор Ember обеспечивает использование сравнительно сложных возможностей, например, вложение шаблонов, но здесь я просто пытаюсь показать, насколько он функционально схож с другими библиотеками.

Просто маршрутизация

В большинстве фреймворков содержится решение для маршрутизации, но в Knockout.js основной акцент делается на привязке данных и предлагается лучшее в своем роде решение, предполагающее использование одной из библиотек JavaScript, единственное назначение которой — маршрутизация. Наиболее распространенные специализированные библиотеки такого рода — SummyJS и HistoryJS. SummyJS работает с браузерами, поддерживающими API History для HTML5, а также URL-хэши для устаревших браузеров (IE 8 и ниже). Библиотека HistoryJS меньше, но поддерживает только API History для HTML5.

Привязка данных

Привязка позволяет вносить изменения в модель данных, которую требуется обновить в представлении или и/или позволяет автоматически обновить модель с учетом изменений, внесенных в представление, причем для этого не требуется никакого дополнительного кода. Однонаправленная привязка данных обычно означает, что изменения, вносимые в модель, распространяются в представление. При двунаправленной привязке данных появляется дополнительная возможность оперативно отражать в модели все изменения, вносимые в представление. Привязка данных избавит вас от массы стереотипного кода, который обычно приходится писать разработчикам. Соответственно, программист может сосредоточиться на решении уникальных задач, свойственных данному приложению.

Пример с AngularJS

Ниже приведен простой пример двунаправленной привязки данных в AngularJS. При наборе текста в поле ввода он будет выводиться на экран сразу же после приветственного сообщения.

<h1>Simple Data Binding with AngularJS</h1>
<br />
<div ng-app>
    Name: <input type="text" ng-model="name" />
    <br /><br />
    Welcome to AngularJS {{name}}
</div>



Пример с KnockoutJS

Фреймворк KnockoutJS действительно сосредотачивается исключительно на привязке данных и используется в рамках наилучшего подобного решения вместе с другими фреймворками и библиотеками, в частности, с DurandalJS для управления дисплеем и History.js или Sammy.js для обработки маршрутизации. Вот пример привязки данных в KnockoutJS.

// Здесь находится моя модель данных
var ViewModel = function(name) {
    this.name = ko.observable(name);   
  };
 
ko.applyBindings(new ViewModel("")); // Так запускается работа Knockout


Пример с Backbone

В Backbone нет автоматической привязки данных, однако ее можно выполнить вручную. По моему опыту, однонаправленная привязка данных, при которой представление обновляется в ответ на изменения, вносимые в модель, является исключительно полезной. Реальные случаи однонаправленной привязки данных от вида к модели встречаются реже (например, вы хотите реализовать живой предпросмотр текста, вводимого пользователем в текстовый редактор). Действительно, привязка от представления к модели может быть полезна, но зачастую причиной изменений представления является информация, вводимая пользователем, а вы хотите успеть реализовать и другую логику прежде, чем эти изменения будут внесены в модель. Например, речь может идти о валидации ввода или фильтрации списка, при которой также требуется запомнить текущий фильтр. Ниже показан простой пример кода, в котором реализованы оба варианта привязки.

var MessageView = Backbone.View.extend({
    template: _.template($('#message-template').html()),    
    events: {
      'keyup #name': 'updateModel'
    },
    updateModel: function(event) {      
      this.model.set({name:$("#name").val()});      
    },
    initialize: function() {      
      this.listenTo(this.model, "change", this.render);       
      this.render();
    },
    render: function() {
        this.$('#message').html(this.template(this.model.toJSON()));
      return this;
    }
  });
   
  var person = new Backbone.Model({name:''});
  messageView = new MessageView({el:   $('#message-container') ,model: person});


Итак, вы слушаете события изменений, происходящие в модели, и вызываете свойство представления render, чтобы модель обновила представление. Аналогично, вы слушаете события «keyup» при вводе и изменяете модель, получая из вводимой информации нужное значение при помощи jQuery и устанавливая его в модели — так, чтобы представление обновило модель. Данный пример помогает составить впечатление о том, сколько кода потребуется, чтобы заработала привязка данных. Также необходимо упомянуть о существовании многочисленных плагинов, поддерживающих привязку данных в Backbone.

Пример с Ember

Привязка данных в Ember выглядит так:

App = Ember.Application.create({});


Фреймворк Ember использует для шаблонизации знакомые нам объекты handlebar, но также включает «помощники ввода», обеспечивающие привязку тех полей ввода, которые встречаются в большинстве форм. В данном примере фигурные скобки {{ заменяют угловые < при вводе, а свойство “name” кавычек не имеет, поэтому помощник знает, что его необходимо привязать. Фреймворк Ember, подобно AngularJS, обеспечивает двунаправленную привязку при помощи минимального количества кода.

Шаблоны/Представления

Шаблон может соответствовать целой HTML-странице, но чаще шаблоны представляют собой более мелкие фрагменты, где на месте будущих динамических данных содержатся выражения-заполнители с уже готовой привязкой. Они могут не включать в себя никакой логики — существует философия, согласно которой в представлениях не должно быть программной логики, либо она может там присутствовать в минимальном количестве. В некоторые шаблоны можно непосредственно встраивать код JavaScript. Шаблоны могут базироваться на модели DOM и использовать DOM для вставки динамических данных на лету, либо для строковой интерпретации HTML: строки HTML используются для оперативной замены динамических элементов.

Библиотеки шаблонов

Среди библиотек, помогающих при шаблонизации, следует назвать Handlebar.js — наиболее популярную из них. Handlebar.js часто используется с Backbone.js и входит в состав Ember.js (с Ember.js можно применять и другие библиотеки шаблонов, но в таком случае значительно падает производительность, и поступать так не рекомендуется). Еще один популярный движок-шаблонизатор называется Mustache.js. UnderscoreJS — вспомогательная библиотека, связанная с фреймворком Backbone.js и включающая, в частности, библиотеку шаблонов, а также массу материала для функционального программирования. Восходящей звездой в этой области можно считать библиотеку Dust.js, которая недавно была взята на вооружение компанией LinkedIn для программирования своих приложений. Кроме того, библиотеки Handlebar.js и Mustache.js часто используются в приложениях, написанных с помощью одних лишь jQuery и AJAX (без всякого JavaScript MVC), когда разработчик понимает, что шаблонизация ему нужна только на клиенте. В составе jQuery разрабатывалась собственная библиотека шаблонов, но на настоящий момент она уже признана нежелательной, и я не рекомендую ею пользоваться.

Истоки Underscore

Все началось с того, как Джереми Ашкенас, создатель BackboneJS, извлек UnderscoreJS из оригинальных версий Backbone, так, чтобы удобные вспомогательные функции можно было использовать и в отрыве от BackboneJS.

Рассмотрим несколько примеров.

Пример с AngularJS

Вот простой пример шаблона в AngularJS.

var templatesExample = angular.module('FunnyAnt.Examples.Templates', []);
templatesExample.controller('HomeController', function ($scope) {
    $scope.greeting = "Welcome to the application.";
});
templatesExample.controller('AboutController', function ($scope) {
    $scope.content = "As a software developer, I've always loved to build things...";
});

templatesExample.config(function ($routeProvider) {
    $routeProvider.
    when('/home', {
        templateUrl: 'embedded.home.html',
        controller: 'HomeController'
    }).
    when('/about', {
        templateUrl: 'embedded.about.html',
        controller: 'AboutController'
    }).
    otherwise({
        redirectTo: '/home'
    });
});


Вероятно, вы заметили, как этот код похож на более ранний пример с маршрутизацией. Здесь только добавлены привязки данных, помогающие понять, как шаблоны могут вам пригодиться в приложении. Шаблоны могут включаться в скриптовые теги основного HTML-файла, чтобы пример выглядел прозрачно, и с ним можно было работать в jsfiddle.net, однако шаблоны могут быть и внешними относительно любого представления Angular.js. В последнем случае на этапе конфигурирования $routeProvider нужно просто указать валидный путь к файлу в свойстве templateUrl.
Стоит упомянуть, что предпочтительный способ обработки шаблонов в масштабных приложениях (где производительность имеет большое значение) заключается в сцеплении шаблонов AngularJS с последующей их регистрацией в Angular $templateCache во время компиляции, причем задача сборки формулируется примерно так.

Пример с Ember

Ниже приведен пример использования шаблонов в Ember.

App = Ember.Application.create({});

App.Router.map(function() {
    // первый параметр относится к шаблону
    this.resource('home', { path: '/' });
    this.resource('about', {path: '/about'});
});

App.HomeRoute = Ember.Route.extend({
    model:function(){
        return{
            greeting: 'Welcome to the application.'
        }
    }
});

App.AboutRoute = Ember.Route.extend({
  model: function(){
      return{
          pagecontent: 'As a software developer, I have always loved to build things...'
      };
  }
});


Маршрут Ember — это объект, сообщающий шаблону, какую модель он должен отображать – именно модель, а не URL. Его можно считать простейшим контроллером для вашего шаблона и ресурса (URL), чья основная задача — загружать модель. Если вам этого недостаточно, и требуется дополнительно еще и сохранять состояние приложения, то понадобится полноценный контроллер.

В фреймворках Ember и AngularJS работа с шаблонами реализована по-разному: строковая модель и модель DOM соответственно. Однако в обоих случаях решаются одни и те же проблемы. Кроме того, интерфейсы и контракты, которые предоставляются в них разработчику, очень схожи. Немного углубившись в детали, отметим, что оба фреймворка используют handlebar-синтаксис для связывания с данными и скриптовые теги или отдельные файлы для хранения шаблонов.

Пример с Backbone

Теперь давайте рассмотрим простой пример работы с шаблонами в Backbone.

var HomeView = Backbone.View.extend({
      template: _.template($("#home-template").html()),
      initialize: function () {
          this.render();
      },
      render: function () {
          this.$el.html(this.template({greeting:"Welcome to Backbone!"}));
      }
  });
  

var AboutView = Backbone.View.extend({
      template: _.template($("#about-template").html()),
      initialize: function () {
          this.render();
      },
      render: function () {
          this.$el.html(this.template({content:"As a software developer, I've always loved to build things..."}));
      }
  });
  
  var AppRouter = Backbone.Router.extend({
      routes: {          
          '': 'homeRoute',
          'home': 'homeRoute',
          'about': 'aboutRoute',          
      },
      homeRoute: function () {
          var homeView = new HomeView();          
          $("#content").html(homeView.el);
      },
      aboutRoute: function () {
          var aboutView = new AboutView();          
          $("#content").html(aboutView.el);
      }
  });

  var appRouter = new AppRouter();
  Backbone.history.start();


Это измененный пример с маршрутизацией. В данном случае HTML не кодируется жестко в свойство template объекта представления; разметка находится на HTML-странице, заключенной в тег script с атрибутом id (браузеры игнорируют скриптовые теги, типы которых им неизвестны — в частности, text/template — поэтому сам шаблон отображаться не будет). Для получения шаблона (HTML-фрагмента) используется селектор jQuery, при помощи которого мы находим элемент по id скриптового тега, выбираем из него innerHTML и присваиваем этот HTML свойству template объекта представления (это просто строка).

При применении такого подхода, при котором шаблоны обрабатываются как обычные строки html, легко себе представить, как можно подставить в приложении Backbone совершенно новую библиотеку на место имеющейся; для этого нужно всего лишь немного изменить реализацию свойства template.
Например, чтобы использовать библиотеку шаблонов Handlebars вместо Underscore, мы обновим у представления свойство template вот так:

template: Handlebars.compile( $("#home-template").html() ),


…а затем обновим синтаксис привязки, используемый в шаблонах, например

{{greeting}}


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

Вот полный пример, в котором библиотека handlebar.js используется для шаблонизации.

var HomeView = Backbone.View.extend({
      template: Handlebars.compile( $("#home-template").html() ),      
      initialize: function () {
          this.render();
      },
      render: function () {
          this.$el.html(this.template({greeting:"Welcome to Backbone!"}));
      }
  });
  

var AboutView = Backbone.View.extend({
      template: Handlebars.compile( $("#about-template").html() ),      
      initialize: function () {
          this.render();
      },
      render: function () {
          this.$el.html(this.template({content:"As a software developer, I've always loved to build things..."}));
      }
  });
  
  var AppRouter = Backbone.Router.extend({
      routes: {          
          '': 'homeRoute',
          'home': 'homeRoute',
          'about': 'aboutRoute',          
      },
      homeRoute: function () {
          var homeView = new HomeView();          
          $("#content").html(homeView.el);
      },
      aboutRoute: function () {
          var aboutView = new AboutView();          
          $("#content").html(aboutView.el);
      }
  });

  var appRouter = new AppRouter();
  Backbone.history.start();


В данном случае нелегко четко отграничить одни концепции от других. Заговаривая о шаблонах, многие специалисты углубляются в производительность шаблонных библиотек, которая во многом связана с обсуждавшейся выше привязкой данных, но также касается и загрузки шаблонов (плюс их предварительной компиляции в JavaScript и т.д…).

В довершение всей этой путаницы шаблоны, как упоминалось выше — это просто HTML, и многие серверные разработчики, имеющие дело с MVC, ассоциируют HTML с представлениями или частичными шаблонами (partials). Однако, представления в Backbone — это код, специальный класс JavaScript, управляющий HTML-фрагментом. Как правило, в представлении Backbone почти не будет разметки за исключением ссылки на шаблон, который обычно располагается вне объекта представления.

Модели

Модели – это клиентская разновидность так называемых бизнес-объектов, объектов предметной области или сущностей. По определению Джереми Ашкенаса, автора Backbone, «модели — сердцевина любого приложения JavaScript, в них содержатся как интерактивные данные, так и значительная часть охватывающей их логики; преобразования, валидация, вычисленные свойства и контроль доступа». Ашкенас также предусмотрительно отмечает, что между этими сущностями и моделями, содержащимися у вас на сервере в Active Record; скорее эти сущности представляют собой более узкую коллекцию, расположенную на клиенте и обладающую дополнительными свойствами, полезными при работе с пользовательским интерфейсом — например, count (счет).

В принципе, идея моделей в клиентских MV*-фреймворках заключается в следующем: создать центральный узел, где будут находиться данные, относящиеся к приложению, а также всевозможные поведения, которые могут быть инкапсулированы вместе с этими данными. Такую модель можно создать на основе архитектур с серверным MVC плюс jQuery, причем данные, относящиеся к модели, обычно хранятся в DOM. Цель создания такой модели – вынести эти данные и состояние за пределы DOM и поместить их в общем месте, откуда их будет легко переиспользовать.

Пример с Backbone

В одном из предыдущих примеров, где рассматривалась привязка данных, мы познакомились с моделями. В принципе, модели содержат данные и хранят их вне DOM, а также порождают события, например, «изменения», на которые соответствующим образом реагируют многочисленные представления, обновляющие пользовательский интерфейс везде, где это необходимо. Итак, у нас есть источник истины, и это не пользовательский интерфейс.

var MessageView = Backbone.View.extend({
template: _.template($('#message-template').html()),
events: {
'click #button': 'updateModel'
},
updateModel: function (event) {
         this.model.set({
              name: $("#name").val()
          });
          $("#name").html('');
      },
      initialize: function () {
          _.bindAll(this, 'render');
          this.listenTo(this.model, "change", this.render);
      },
      render: function () {
          this.$('#message').html(this.template(this.model.toJSON()));
          return this;
      }
  });

  var NameView = Backbone.View.extend({
      template: _.template($('#name-template').html()),
      initialize: function () {
          _.bindAll(this, 'render');
          this.listenTo(this.model, "change", this.render);
      },
      render: function () {
          this.$el.html(this.template(this.model.toJSON()));
          return this;
      }
  });

  var Person = Backbone.Model.extend({
      defaults: {
          name: ''
      }
  });

  var person = new Person();

  var messageView = new MessageView({
      el: $('#message-container'),
      model: person
  });

  var nameView = new NameView({
      el: $('#name-container'),
      model: person
  });



Я немного изменил вышеприведенный пример с привязкой данных, добавив новый шаблон и представление, связанное с тем же объектом модели Person, что и шаблон. Выше я динамически объявлял модель Person, чтобы не усложнять код, но теперь я добавляю вызов метода Backbone.Model.extend(), чтобы продемонстрировать, как создать прототип для модели, который может многократно использоваться — подобно классам в классических языках.

Обратите внимание: оба представления слушают одну один и тот же объект модели Person (событие изменения) и обновляются. Если источник данных всего один, то многочисленные вызовы к конкретным элементам DOM можно инкапсулировать в собственные аккуратные представления, а модель сможет обслуживать их все.

Обратите внимание, как используются методы доступа (установщики и получатели) для того, чтобы в вышеприведенном примере запускались события изменений… о таком соглашении часто забывают.

Пример с AngularJS

Идея одной модели, хранящей истинную информацию о «состоянии» вашего приложения, существует в AngularJS, однако AngularJS позволяет использовать в качестве моделей объекты POJO, а затем «под капотом» добавляет наблюдатели к любым свойствам, прикрепляемым к объекту $scope и декларативно привязываемым к представлению с использованием директивы «ng-model». Затем эти наблюдатели автоматически оповещают другие компоненты приложения, прикрепленные к этой же модели, и эти элементы DOM «знают», как им следует обновиться. В общем, здесь происходит немало «магии», но команда разработчиков AngularJS настаивает, что это «белая магия».
Вот обновленный пример на AngularJS с привязкой данных. Здесь показано, как обновляются фрагменты представления.

<h1>Simple Data Binding with AngularJS</h1>
<br />
<div ng-app>
    Name: <input type="text" ng-model="person.name" />
    <br /><br />
    Welcome to AngularJS {{person.name}}
    <br/>
    Person: {{person.name}}
</div>


AngularJS создает для вас объект person в области видимости, когда привязка данных происходит с атрибутом ng-model. Итак, этот пример очень лаконичен и не содержит JavaScript.
Возможно, здесь я немного слукавил: ведь мы не создавали множества контроллеров для управления различными частями представления, как это делалось в Backbone; однако, так или иначе, для решения задачи в AngularJS требуется гораздо меньше кода.

Хранение данных

Пример с AngularJS

AngularJS обрабатывает данные двумя разными способами. Во-первых, он позволяет вручную выполнять вызовы AJAX в манере, очень напоминающей функцию $.ajax из jQuery, через $http. Во вторых, если ваш интерфейс базы данных является чистым RESTful-сервисом, AngularJS предоставляет класс $resource, благодаря которому вызовы RESTful-сервиса получаются крайне лаконичными.

Пример $http

app.factory('myService', function($http) {
   return {
     getFooOldSchool: function(callback) {
       $http.get('foo.json').success(callback);
     }
   }
});
 
app.controller('MainCtrl', function($scope, myService) {
  myService.getFooOldSchool(function(data) {
     $scope.foo = data;
  });
});

Пример $resource 
var Todo = $resource('/api/1/todo/:id');
 
// создаем todo
var todo1 = new Todo();
todo1.foo = 'bar';
todo1.something = 123;
todo1.$save();
 
// получаем и обновляем todo
var todo2 = Todo.get({id: 123});
todo2.foo += '!';
todo2.$save();
 
// удаляем todo
Todo.$delete({id: 123});


Пример с Backbone

В Backbone предполагается, что вы взаимодействуете с RESTful API, но в противном случае фреймворк позволяет переопределить один из методов Backbone.sync(). Вы сообщаете вашей модели, где ресурс находится на сервере (URL), после чего можете просто вызвать save.

var UserModel = Backbone.Model.extend({
urlRoot: '/user',
defaults: {
name: '',
email: ''
}
    });
    var user = new Usermodel();
    // Обратите внимание: у нас не задан `id`
    var userDetails = {
        name: 'Craig',
        email: 'craigmc@funnyant.com'
    };
    // Поскольку мы не установили `id`, сервер вызовет 
    // POST /user с полезной нагрузкой {name:'Craig', email: 'craigmc@funnyant.com'}
    // Сервер должен сохранить данные и вернуть ответ, содержащий новый `id`
    user.save(userDetails, {
        success: function (user) {
            alert(user.toJSON());
        }
    })


Пример с Ember

Во фреймворке Ember есть модуль Ember Data, технически не входящий в состав ядра этого фреймворка, но призванный обеспечить более надежное ведение истории сохраняемости/хранения данных. Он предоставляет многие возможности, присущие серверным ORM наподобие ActiveRecord, но разработан именно для взаимодействия с JavaScript и работы в условиях браузера. На момент написания статьи команда разработчиков Ember Core готовится выпустить версию v1.0, но пока не сделала этого, так что в большинстве проектов Ember просто применяются методы $.ajax из jQuery, точно как выше в случае с AngularJS мы использовали $http.

Все мы в одной лодке

В этой статье были подробно рассмотрены MV*-фреймворки JavaScript, функционал, предоставляемый в этих фреймворках. Я попытался донести идею о том, что, в сущности, все эти фреймворки очень похожи. Стоит вам разобраться с отдельными возможностями и понять, как они стыкуются друг с другом – и вы легко сможете изучить несколько фреймворков, а затем выбрать из них тот, который оптимально подходит для вашего проекта.

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

Книги по фреймворкам JavaScript

Издательский дом «Питер»
183,00
Компания
Поделиться публикацией

Похожие публикации

Комментарии 10

    +10
    многоранную

    Не исправляйте эту опечатку! Это тот случай, когда опечатка лучше подходит по смыслу :)
      +5
      Не очень понятен смысл опроса в конце статьи.
      Вы же обозначили тему, говорите о сходствах, об общих чертах.
      Вот и сделайте книгу об общих подходах и паттернах клиентских приложений в браузере. Примеры пусть будут на разных технологиях.
      Такая книга будет гораздо полезнее для интересующегося человека. После неё он сможет в короткий срок освоить любой необходимый фреймворк.
        0
        Они не делают книги, они их издают. Т.е. скорее всего переводят и издают. И надо выбирать из того что имеется (уже издано на других языках).
        +4
        Перевод зарубежных книг по Web-технологиям — дело неблагодарное. Не успеете Вы выпустить Pro AngularJS от Адама Фримена или ng-book от Ari Lerner'а, как уже выйдёт более новая версия фреймворка или оригинала, и книги покупать не будут.
        Если и публиковать, то только в электронном виде. С другой стороны, люди, работающие с Angular, как мне кажется, без труда справятся и с английской версией издания, им переводная вовсе ни к чему (разве что для начинающих с тройкой по английскому или тем, кто, как и я, в школе не имел права выбирать язык и учил немецкий / французский / предложите своё).
          +2
          Так как я истинный приверженец Backbone, не могу не заметить, что Backbone ставить в один ряд или хотя бы даже сравнивать с фреймворками не стоит. Backbone одним только своим видом пропагандирует распределенную разработку и является библиотекой с набором конструкций на основе которых вы проектируете свою собственную архитектуру или же более абстрактную вещь как фреймворк.
            +1
            Лучше добавьте в сравнение react.js, как компонентный фреймворк
              +1
              Считаю, что книги нужны по более фундаментальным темам. По фреймворкам по идее должна быть нормальная документация от авторов, всё остальное — рецепты для чайников.
              А статья отличная, как-то сразу так оп и въехал в ember =) Спасибо!
                0
                Перевод неплохой, но почему вы не стали приводить в статье html фрагменты из оригинала, а ограничились только javascript?
                  +1
                  Извините, только для сокращения объема
                    0
                    А в разделе «Привязка данных», в случае с Ember, кусок примера случайно не потерялся?

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

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