Субъективный взгляд
  на несколько JS
   фреймворков
     k.likhter@2gis.ru
don't call us — we'll call you
                    — JavaScript
Google Closure Library
Все видели продукты,
 сделанные на нём
Все видели продукты,
 сделанные на нём
     Google [A-Za-z]+
Это не фреймворк
Это не фреймворк
  а набор инструментов
Очень низкоуровнево
Очень низкоуровнево
    это и плюс, и минус
Избыточное
   именование
Исправляется собственными
      наработками
tutorial.notepad.Note.prototype.makeNoteDom = function() {
     // Create DOM structure to represent the note.
     this.headerElement = goog.dom.createDom('div',
         {'style': 'background-color:#EEE'}, this.title);
     this.contentElement = goog.dom.createDom('div', null, this.content);
     var newNote = goog.dom.createDom('div', null,
         this.headerElement, this.contentElement);




     // Add the note's DOM structure to the document.
     goog.dom.appendChild(this.parent, newNote);
};
// jquery
$('#foo').click(function(){
    $(this).parent().next('.d2').text('Hello');
});




// google closure
goog.dom.getElement('foo').onclick = function(){
    var div = goog.dom.getAncestorByClass(this, 'd1');
    var nextDiv = goog.dom.getNextElementSibling(div);
    goog.dom.setTextContent(nextDiv, 'Hello');
}
// google closure
var node = goog.dom.getElement('mytarget');
node.style.backgroundColor = 'blue';
node.style.backgroundColor = 'red';




// pure javascript
var node = document.getElementById('mytarget');
node.style.backgroundColor = 'blue';
node.style.backgroundColor = 'red';
// google closure
var node = goog.dom.getElement('mytarget');
node.style.backgroundColor = 'blue';
node.style.backgroundColor = 'red';




// pure javascript
var node = document.getElementById('mytarget');
node.style.backgroundColor = 'blue';
node.style.backgroundColor = 'red';



... причем второй вариант работает быстрее (jsperf.com)
  на втором месте — pure javascript, на третьем — jQuery
Не всё так страшно!
Не всё так страшно!
Множество всего реализовано: отладка,
история, i18n, storage, testing, система
          модулей и прочее
Оптимизированный на
  скорость JS код
switch (node.tagName) {
    case goog.dom.TagName.APPLET:
    case goog.dom.TagName.AREA:
    case goog.dom.TagName.BR:
    case goog.dom.TagName.COL:
    case goog.dom.TagName.FRAME:
    case goog.dom.TagName.HR:
    case goog.dom.TagName.IMG:
    case goog.dom.TagName.INPUT:
    case goog.dom.TagName.IFRAME:
    case goog.dom.TagName.ISINDEX:
    case goog.dom.TagName.LINK:
    case goog.dom.TagName.NOFRAMES:
    case goog.dom.TagName.NOSCRIPT:
    case goog.dom.TagName.META:
    case goog.dom.TagName.OBJECT:
    case goog.dom.TagName.PARAM:
    case goog.dom.TagName.SCRIPT:
    case goog.dom.TagName.STYLE:
      return false;
}
return true;
                                      Google: "How not to write JavaScript"
Google Closure
  Compiler
     wins
Google Closure
       Templates
Компилируются как на серверной, так и
       на клиентской стороне!
Google Closure Templates Compiler для
         ускорения работы.
summary
 Google Closure Library
+ Google           - муторно
+ низкоуровнево    - нет готовых
+ тру разработка      хранилищ списков
+ своя классовая   - нет
  модель              адаптированной
+ свои события        архитектуры
+ свой i18n
+ шаблоны - свой
  продукт
ExtJS
Не все видели
продукты, но активно
   используется
    Microsoft, Intel, HP etc
Полноценный
 фреймворк
Своя система классов
    включая MVC подход
Своя система
        хранилищ
автоматическое обновление view и так
              далее
Гигантский набор
 инструментов для
создания связанных
        view
более гибких, чем автоматическое
  обновления UI в knockout.js
Ext.create('Ext.data.Store', {
    storeId:'simpsonsStore',
    fields:['name', 'email', 'phone'],
    data:{'items':[
        { 'name': 'Lisa', "email":"lisa@simpsons.com",      "phone":"555-111-1224" },
        { 'name': 'Bart', "email":"bart@simpsons.com",      "phone":"555-222-1234" },
        { 'name': 'Homer', "email":"home@simpsons.com",     "phone":"555-222-1244" },
        { 'name': 'Marge', "email":"marge@simpsons.com",    "phone":"555-222-1254" }
    ]},
    proxy: {
        type: 'memory',
        reader: {
             type: 'json',
             root: 'items'
        }
    }
});



Ext.create('Ext.grid.Panel', {
    title: 'Simpsons',
    store: Ext.data.StoreManager.lookup('simpsonsStore'),
    columns: [
        { text: 'Name', dataIndex: 'name' },
        { text: 'Email', dataIndex: 'email', flex: 1 },
        { text: 'Phone', dataIndex: 'phone' }
    ],
    height: 200,
    width: 400,
    renderTo: Ext.getBody()
});
Ext.create('Ext.data.Store', {                                      хранилище данных
    storeId:'simpsonsStore',
    fields:['name', 'email', 'phone'],
    data:{'items':[
        { 'name': 'Lisa', "email":"lisa@simpsons.com", "phone":"555-111-1224" },
        { 'name': 'Bart', "email":"bart@simpsons.com", "phone":"555-222-1234" },
        { 'name': 'Homer', "email":"home@simpsons.com", "phone":"555-222-1244" },
        { 'name': 'Marge', "email":"marge@simpsons.com", "phone":"555-222-1254" }
    ]},
    proxy: {
        type: 'memory',                    описание механизма сохранения данных
        reader: {                          (ленивая инициализация через JS объект)
             type: 'json',
             root: 'items'
        }                                  Может быть создана через
    }                                      Ext.create('Ext.data.store.proxy.Memory', { ...
});                                        })
                                           Ext.create('Ext.data.store.proxy.Json', { ...
                                           })

Ext.create('Ext.grid.Panel', {
    title: 'Simpsons',                                            View, зависящая от хранилища данных
    store: Ext.data.StoreManager.lookup('simpsonsStore'),
    columns: [
        { text: 'Name', dataIndex: 'name' },
        { text: 'Email', dataIndex: 'email', flex: 1 },
        { text: 'Phone', dataIndex: 'phone' }
    ],
    height: 200,
    width: 400,
    renderTo: Ext.getBody()
});
Свой шаблонизатор
(по принципу шаблонизатора J.Resig)
Самая лучшая в мире
    документация
и расширение проекта по документации
Но!
Фреймворк не для
    этого!
А для создания
windows-подобного GUI
А для создания
windows-подобного GUI
 то есть придётся писать свои view на
      основе уже существующих
Платная для не
OpenSource проектов
  Расшарим наш исходник? :)
summary
 ExtJS
+ отличная логика,   - не для того
  которой стоит      - платная
  придерживаться     - достаточно
+ отличная              сложная в
  документация          освоении
+ отличные           - на сервеной части
  инструменты           жизни нет
summary
 Ext.Core
+ отличная логика,   - достаточно
  которой стоит          сложная в
  придерживаться         освоении
+ отличная           -   на серверной части
  документация           жизни нет
+ отличные           -   нет отличных
  инструменты            инструментов,
                         нужно писать
                         самим
Backbone
Backbone
назад кость?! о_О
Backbone
спинной хребет, твёрдость характера,
          главная опора
Все видели продукты,
 сделанные на нём
  LinkedIn Mobile, Foursquare
Полноценный
        фреймворк
(вероятно, сделано по подобию ExtJS)
Классовая организация
  смешанная, в том числе MVC
// mixins
var object = {};
_.extend(object, Backbone.Events);
object.on("alert", function(msg) {
  alert("Triggered " + msg);
});
object.trigger("alert", "an event");



// true extending
var Sidebar = Backbone.Model.extend({
  promptColor: function() {
      var cssColor = prompt("Please enter a CSS color:");
      this.set({color: cssColor});
  }
});
// mixins                                    Событийная модель!
var object = {};
_.extend(object, Backbone.Events);
object.on("alert", function(msg) {
  alert("Triggered " + msg);
});
object.trigger("alert", "an event");



// true extending
var Sidebar = Backbone.Model.extend({
  promptColor: function() {
      var cssColor = prompt("Please enter a CSS color:");
      this.set({color: cssColor});
  }
});
Своя система
 хранилищ
var collection = new Backbone.Collection([
  {name: "Tim", age: 5},
  {name: "Ida", age: 26},
  {name: "Rob", age: 55}
]);



// or



var collection = new Backbone.Collection({
      model: Book,
      items: [...]
      storage: ... // e.g. localStorage plugin
});



alert(JSON.stringify(collection));
Автоматический CRUD
// Backbone.sync(method, model, opts);




// e.g.
Backbone.sync('read', Books);
Инструмент создания
       view
var DocumentRow = Backbone.View.extend({
  tagName: "li",
  className: "document-row",
  events: {
       "click .icon":          "open",
       "click .button.edit":   "openEditDialog"
  },
  render: function() {
       ...
  }
});




var doc = Documents.first();




new DocumentRow({
  model: doc,
  id: "document-row-" + doc.id
});
Шаблоны - _.template
  Вероятно, можно подменить
Шаблоны - _.template
С бубном можно отрендерить на node.js
Плохая документация
Нет примеров, отсутствие официального
              туториала
summary
 Backbone
+ попытка повторить       - плохая
  ExtJS                      документация
+ наличие                 - местами не очень
  инструментов для           логичная
  создания                - достаточно сложная
  model/view/controller      в освоении
+ логичный код            - нет нара
AngularJS
Новая разработка
    Google
Ближе всего к
 knockoutjs
Декларативные
          биндинги
(вообще, какой-то неведомый паттерн MVW)
Крайне умная
шаблонная система
Прекомпилирование шаблонов,
         например
<body ng-controller="PhoneListCtrl">
   <ul>
      <li ng-repeat="phone in phones">
        {{phone.name}}
        <p>{{phone.snippet}}</p>
      </li>
  </ul>
</body>



// а так же
<ng-repeat>
...
</ng-repeat>



// или
<li class="ng-repeat: phone in phones">
...
</li>
Более строгое
разграничение по
    модулям
   И вообще — МVC!
Встроенная система
    тестирования
Пишешь модуль — сразу же пишешь тест
Куча синтаксического
       сахара
// Provide the wiring information in a module
angular.module('myModule', []).


 // Teach the injector how to build a 'greeter'
 // Notice that greeter itself is dependent on '$window'
 factory('greeter', function($window) {
   // This is a factory function, and is responsible for
   // creating the 'greet' service.
   return {
        greet: function(text) {
            $window.alert(text);
        }
   };
 }).


// New injector is created from the module.
// (This is usually done automatically by angular bootstrap)
var injector = angular.injector('myModule');


// Request any dependency from the injector
var greeter = injector.get('greeter');
Поддержка i18n из
       коробки
поддерживает pluralize, разбиение на
             локали
    (как следствие, полная совместимость с gettext, если вдруг)
Отсутствие готовых
крупных приложений
 (та же проблема, что и knockout)
Нет зависимости от
сторонних библиотек
  jQuery — for DOM manipulating
 AngularJS — for web-app building
angular-headless
 (и прочие эксперименты разной успешности)



      ну вы поняли :)
Документация —
 очень-очень!
Об автоматическом
     сохранении,
транспортах, прокси —
     не слышали
  Но можно реализовать самому.
summary
 AngularJS
+ Google              - Нет уверенности:
+ Похож на knockout     * 350+ issues / ghub
  + Syntax sugar
+ "На все случаи      ? Шаблоны на
  жизни"                сервере —
  + Отличнейшая         сторонний продукт
  документация
Спасибо!
74 слайда — не так уж и много, правда? :-)

Js fuckworks

  • 1.
    Субъективный взгляд на несколько JS фреймворков k.likhter@2gis.ru
  • 2.
    don't call us— we'll call you — JavaScript
  • 3.
  • 4.
    Все видели продукты, сделанные на нём
  • 5.
    Все видели продукты, сделанные на нём Google [A-Za-z]+
  • 6.
  • 7.
    Это не фреймворк а набор инструментов
  • 8.
  • 9.
    Очень низкоуровнево это и плюс, и минус
  • 10.
    Избыточное именование Исправляется собственными наработками
  • 11.
    tutorial.notepad.Note.prototype.makeNoteDom = function(){ // Create DOM structure to represent the note. this.headerElement = goog.dom.createDom('div', {'style': 'background-color:#EEE'}, this.title); this.contentElement = goog.dom.createDom('div', null, this.content); var newNote = goog.dom.createDom('div', null, this.headerElement, this.contentElement); // Add the note's DOM structure to the document. goog.dom.appendChild(this.parent, newNote); };
  • 12.
    // jquery $('#foo').click(function(){ $(this).parent().next('.d2').text('Hello'); }); // google closure goog.dom.getElement('foo').onclick = function(){ var div = goog.dom.getAncestorByClass(this, 'd1'); var nextDiv = goog.dom.getNextElementSibling(div); goog.dom.setTextContent(nextDiv, 'Hello'); }
  • 13.
    // google closure varnode = goog.dom.getElement('mytarget'); node.style.backgroundColor = 'blue'; node.style.backgroundColor = 'red'; // pure javascript var node = document.getElementById('mytarget'); node.style.backgroundColor = 'blue'; node.style.backgroundColor = 'red';
  • 14.
    // google closure varnode = goog.dom.getElement('mytarget'); node.style.backgroundColor = 'blue'; node.style.backgroundColor = 'red'; // pure javascript var node = document.getElementById('mytarget'); node.style.backgroundColor = 'blue'; node.style.backgroundColor = 'red'; ... причем второй вариант работает быстрее (jsperf.com) на втором месте — pure javascript, на третьем — jQuery
  • 15.
    Не всё такстрашно!
  • 16.
    Не всё такстрашно! Множество всего реализовано: отладка, история, i18n, storage, testing, система модулей и прочее
  • 17.
    Оптимизированный на скорость JS код
  • 18.
    switch (node.tagName) { case goog.dom.TagName.APPLET: case goog.dom.TagName.AREA: case goog.dom.TagName.BR: case goog.dom.TagName.COL: case goog.dom.TagName.FRAME: case goog.dom.TagName.HR: case goog.dom.TagName.IMG: case goog.dom.TagName.INPUT: case goog.dom.TagName.IFRAME: case goog.dom.TagName.ISINDEX: case goog.dom.TagName.LINK: case goog.dom.TagName.NOFRAMES: case goog.dom.TagName.NOSCRIPT: case goog.dom.TagName.META: case goog.dom.TagName.OBJECT: case goog.dom.TagName.PARAM: case goog.dom.TagName.SCRIPT: case goog.dom.TagName.STYLE: return false; } return true; Google: "How not to write JavaScript"
  • 19.
    Google Closure Compiler wins
  • 20.
    Google Closure Templates Компилируются как на серверной, так и на клиентской стороне! Google Closure Templates Compiler для ускорения работы.
  • 21.
    summary Google ClosureLibrary + Google - муторно + низкоуровнево - нет готовых + тру разработка хранилищ списков + своя классовая - нет модель адаптированной + свои события архитектуры + свой i18n + шаблоны - свой продукт
  • 22.
  • 23.
    Не все видели продукты,но активно используется Microsoft, Intel, HP etc
  • 24.
  • 25.
    Своя система классов включая MVC подход
  • 26.
    Своя система хранилищ автоматическое обновление view и так далее
  • 27.
    Гигантский набор инструментовдля создания связанных view более гибких, чем автоматическое обновления UI в knockout.js
  • 28.
    Ext.create('Ext.data.Store', { storeId:'simpsonsStore', fields:['name', 'email', 'phone'], data:{'items':[ { 'name': 'Lisa', "email":"lisa@simpsons.com", "phone":"555-111-1224" }, { 'name': 'Bart', "email":"bart@simpsons.com", "phone":"555-222-1234" }, { 'name': 'Homer', "email":"home@simpsons.com", "phone":"555-222-1244" }, { 'name': 'Marge', "email":"marge@simpsons.com", "phone":"555-222-1254" } ]}, proxy: { type: 'memory', reader: { type: 'json', root: 'items' } } }); Ext.create('Ext.grid.Panel', { title: 'Simpsons', store: Ext.data.StoreManager.lookup('simpsonsStore'), columns: [ { text: 'Name', dataIndex: 'name' }, { text: 'Email', dataIndex: 'email', flex: 1 }, { text: 'Phone', dataIndex: 'phone' } ], height: 200, width: 400, renderTo: Ext.getBody() });
  • 29.
    Ext.create('Ext.data.Store', { хранилище данных storeId:'simpsonsStore', fields:['name', 'email', 'phone'], data:{'items':[ { 'name': 'Lisa', "email":"lisa@simpsons.com", "phone":"555-111-1224" }, { 'name': 'Bart', "email":"bart@simpsons.com", "phone":"555-222-1234" }, { 'name': 'Homer', "email":"home@simpsons.com", "phone":"555-222-1244" }, { 'name': 'Marge', "email":"marge@simpsons.com", "phone":"555-222-1254" } ]}, proxy: { type: 'memory', описание механизма сохранения данных reader: { (ленивая инициализация через JS объект) type: 'json', root: 'items' } Может быть создана через } Ext.create('Ext.data.store.proxy.Memory', { ... }); }) Ext.create('Ext.data.store.proxy.Json', { ... }) Ext.create('Ext.grid.Panel', { title: 'Simpsons', View, зависящая от хранилища данных store: Ext.data.StoreManager.lookup('simpsonsStore'), columns: [ { text: 'Name', dataIndex: 'name' }, { text: 'Email', dataIndex: 'email', flex: 1 }, { text: 'Phone', dataIndex: 'phone' } ], height: 200, width: 400, renderTo: Ext.getBody() });
  • 30.
  • 31.
    Самая лучшая вмире документация и расширение проекта по документации
  • 32.
  • 33.
  • 34.
  • 35.
    А для создания windows-подобногоGUI то есть придётся писать свои view на основе уже существующих
  • 36.
    Платная для не OpenSourceпроектов Расшарим наш исходник? :)
  • 37.
    summary ExtJS + отличнаялогика, - не для того которой стоит - платная придерживаться - достаточно + отличная сложная в документация освоении + отличные - на сервеной части инструменты жизни нет
  • 38.
    summary Ext.Core + отличнаялогика, - достаточно которой стоит сложная в придерживаться освоении + отличная - на серверной части документация жизни нет + отличные - нет отличных инструменты инструментов, нужно писать самим
  • 39.
  • 40.
  • 41.
    Backbone спинной хребет, твёрдостьхарактера, главная опора
  • 42.
    Все видели продукты, сделанные на нём LinkedIn Mobile, Foursquare
  • 43.
    Полноценный фреймворк (вероятно, сделано по подобию ExtJS)
  • 44.
    Классовая организация смешанная, в том числе MVC
  • 45.
    // mixins var object= {}; _.extend(object, Backbone.Events); object.on("alert", function(msg) { alert("Triggered " + msg); }); object.trigger("alert", "an event"); // true extending var Sidebar = Backbone.Model.extend({ promptColor: function() { var cssColor = prompt("Please enter a CSS color:"); this.set({color: cssColor}); } });
  • 46.
    // mixins Событийная модель! var object = {}; _.extend(object, Backbone.Events); object.on("alert", function(msg) { alert("Triggered " + msg); }); object.trigger("alert", "an event"); // true extending var Sidebar = Backbone.Model.extend({ promptColor: function() { var cssColor = prompt("Please enter a CSS color:"); this.set({color: cssColor}); } });
  • 47.
  • 48.
    var collection =new Backbone.Collection([ {name: "Tim", age: 5}, {name: "Ida", age: 26}, {name: "Rob", age: 55} ]); // or var collection = new Backbone.Collection({ model: Book, items: [...] storage: ... // e.g. localStorage plugin }); alert(JSON.stringify(collection));
  • 49.
  • 50.
    // Backbone.sync(method, model,opts); // e.g. Backbone.sync('read', Books);
  • 51.
  • 52.
    var DocumentRow =Backbone.View.extend({ tagName: "li", className: "document-row", events: { "click .icon": "open", "click .button.edit": "openEditDialog" }, render: function() { ... } }); var doc = Documents.first(); new DocumentRow({ model: doc, id: "document-row-" + doc.id });
  • 53.
    Шаблоны - _.template Вероятно, можно подменить
  • 54.
    Шаблоны - _.template Сбубном можно отрендерить на node.js
  • 55.
    Плохая документация Нет примеров,отсутствие официального туториала
  • 56.
    summary Backbone + попыткаповторить - плохая ExtJS документация + наличие - местами не очень инструментов для логичная создания - достаточно сложная model/view/controller в освоении + логичный код - нет нара
  • 57.
  • 58.
  • 59.
  • 60.
    Декларативные биндинги (вообще, какой-то неведомый паттерн MVW)
  • 61.
  • 62.
    <body ng-controller="PhoneListCtrl"> <ul> <li ng-repeat="phone in phones"> {{phone.name}} <p>{{phone.snippet}}</p> </li> </ul> </body> // а так же <ng-repeat> ... </ng-repeat> // или <li class="ng-repeat: phone in phones"> ... </li>
  • 63.
    Более строгое разграничение по модулям И вообще — МVC!
  • 64.
    Встроенная система тестирования Пишешь модуль — сразу же пишешь тест
  • 65.
  • 66.
    // Provide thewiring information in a module angular.module('myModule', []). // Teach the injector how to build a 'greeter' // Notice that greeter itself is dependent on '$window' factory('greeter', function($window) { // This is a factory function, and is responsible for // creating the 'greet' service. return { greet: function(text) { $window.alert(text); } }; }). // New injector is created from the module. // (This is usually done automatically by angular bootstrap) var injector = angular.injector('myModule'); // Request any dependency from the injector var greeter = injector.get('greeter');
  • 67.
    Поддержка i18n из коробки поддерживает pluralize, разбиение на локали (как следствие, полная совместимость с gettext, если вдруг)
  • 68.
    Отсутствие готовых крупных приложений (та же проблема, что и knockout)
  • 69.
    Нет зависимости от стороннихбиблиотек jQuery — for DOM manipulating AngularJS — for web-app building
  • 70.
    angular-headless (и прочиеэксперименты разной успешности) ну вы поняли :)
  • 71.
  • 72.
    Об автоматическом сохранении, транспортах, прокси — не слышали Но можно реализовать самому.
  • 73.
    summary AngularJS + Google - Нет уверенности: + Похож на knockout * 350+ issues / ghub + Syntax sugar + "На все случаи ? Шаблоны на жизни" сервере — + Отличнейшая сторонний продукт документация
  • 74.
    Спасибо! 74 слайда —не так уж и много, правда? :-)