Опыт разработки эффективного SPA

2,447 views
2,441 views

Published on

Доклад с седьмой конференции DotNetConf

0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
2,447
On SlideShare
0
From Embeds
0
Number of Embeds
5
Actions
Shares
0
Downloads
16
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide

Опыт разработки эффективного SPA

  1. 1. 7-я конференция .NET разработчиков 22 сентября 2013 www.dotnetconf.ru Опыт разработки эффективного SPA Евгений Абросимов ByndyuSoft twitter.com/abrosimov
  2. 2. Немного истории (function($, window, document, undefined) { 'sue strict'; $('#someElement').somePlugin({ option1: value1, ... opntionN: valueN }); $('.someClass').doSomething(); $('#someContainer').on('click', '.elemInside', function(e) { e.stopPrapagation(); // Прочие действия }); })(jQuery, this, document); Опыт разработки эффективного SPA, Евгений Абросимов 2
  3. 3. Немного истории var $app = $app || { core: {}, ui: {}, config: {}, utilities: {}, login: {}, registration: {}, //... }; Опыт разработки эффективного SPA, Евгений Абросимов 3
  4. 4. Что такое SPA? Single Page Application – это приложение, которое выполняется в браузере. SPA базируется на HTML/JS/CSS/JSON. SPA жестко делит клиентскую и серверную логику. SPA общается с сервером только чистыми данными. Разметка хранится на стороне клиента в шаблонах. Перезагрузки страницы не происходит. Опыт разработки эффективного SPA, Евгений Абросимов 4
  5. 5. SPA vs MPA
  6. 6. Примеры SPA Опыт разработки эффективного SPA, Евгений Абросимов 6
  7. 7. Критерии эффективности 1. Модульность системы. 2. Однозначное определение местоположения пользователя роутом. 3. Событийная модель коммуникации. 4. Минимизированное количество изменений DOM. 5. Отсутствие утечек памяти. 6. Минимизированное количество запросов к серверу. Опыт разработки эффективного SPA, Евгений Абросимов 7
  8. 8. Фундамент для эффективного SPA 1. Минимальное время для старта SPA. Минимум запросов к серверу за ресурсами: images.png, style.css, script.js. 2. Эффективная верстка. Верстка должна разделять идентификаторы и классы, которые отвечают за логику работы, и классы, которые отвечают за отображение макета приложения в браузере. Идеально: логика на id, верстка на class. Использование быстрых селекторов. Минимизация объема разметки. 3. Хороший Javascript Опыт разработки эффективного SPA, Евгений Абросимов 8
  9. 9. Backbone.js Это javascript-библиотека, которая реализует паттерн MVW (Model-View-Whatever). Создана была Джереми Ашкенасом (DocumentCloud, CoffeeScript, Underscore). Первый релиз был выпущен 13 октября 2010 года. Актуальная версия: v1.0.0 (20 марта 2013) forks: 3236 / stars: 15723 Зависит от: jQuery(Zepto) и Underscore.js http://backbonejs.org/docs/backbone.html Опыт разработки эффективного SPA, Евгений Абросимов 9
  10. 10. Сущности backbone.js Backbone.Model 1. Model – это единица данных. Отвечает за получение, отправку, хранение, валидацию и прочие манипуляции с данными какой то сущности. var sampleModel = Backbone.Model.extend({ url: '/path/to/data', defaults: { //Значения атрибутов по-умолчанию }, initialize: function () { //Конструктор модели }, someMethod: function () { //Тело метода } }); Опыт разработки эффективного SPA, Евгений Абросимов 10
  11. 11. Сущности backbone.js Backbone.Collection 2. Collection – это массив или список моделей. Отвечает за получение и отправку набора данных какой то сущности, а так же за манипуляции с моделями (создание, обновление, удаление). Работает только с моделями определенного типа. var sampleCollection = Backbone.Collection.extend({ url: '/path/to/data', model: sampleModel, initialize: function () { //Конструктор коллекции }, filteredByName: function (name) { return this.filter(function (model) { return model.get(‘name') === name; }); }, }); Опыт разработки эффективного SPA, Евгений Абросимов 11
  12. 12. Сущности backbone.js Backbone.View 3. View – это представление модели или коллекций. Отвечает за рендеринг модели или коллекции, работу с шаблонами, обработку событий и другое. var sampleView = Backbone.View.extend({ tagName: 'div', className: 'someDiv', initialize: function () { //Конструктор представления this.model.on('change', this.render, this); }, render: function () { var data = this.model.toJSON(); this.$el.html(_.template(this.template, data)); return this; } }); Опыт разработки эффективного SPA, Евгений Абросимов 12
  13. 13. Сущности backbone.js Backbone.Router 4. Router предоставляет методы для маршрутизации на стороне клиента, а также связывания этих действий с событиями. var sampleRouter = Backbone.Router.extend({ routes: { //Словарь роутов и экшенов 'index': 'index', 'search/:id': 'search' }, initialize: function () { //Конструктор роута }, index: function () { //Тело метода }, search: function (id) { //Тело метода } }); Опыт разработки эффективного SPA, Евгений Абросимов 13
  14. 14. Модульная структура Require.js – это javascript-библиотека, которая реализует подход Asynchronous Module Definition. define() – описание модуля. require() – подтягивание зависимости. http://requirejs.org/ v2.1.8 / forks: 693 / stars: 4528 <script type="text/javascript" src="assets/require/require.min.js" datamain="app/packages.js"></script> Опыт разработки эффективного SPA, Евгений Абросимов 14
  15. 15. Модульная структура define('mymodule',['jquery'], function ($) { return { foo: 'bar' }; } ); или define('mymodule', function (require) { var $ = require('jquery'); return { foo: 'bar' }; } ); Опыт разработки эффективного SPA, Евгений Абросимов 15
  16. 16. Событийная модель коммуникации Как обеспечить коммуникацию модулей? Использовать события! $('#someElement').on('someEvent', function () { //Тело обработчика }); ... $('#someElement').trigger('someEvent'); Анти-паттерн! Опыт разработки эффективного SPA, Евгений Абросимов 16
  17. 17. Событийная модель коммуникации Backbone.Events Backbone.Events – это встроенные в backbone объект, который реализует паттерн Наблюдатель (Observer). var vent = _.extend({}, Backbone.Events); vent.on('smth', function (data) { console.log(data); //Object {hello: "world"} }); vent.trigger('smth', { hello: 'world' }); vent.off('smth'); Опыт разработки эффективного SPA, Евгений Абросимов 17
  18. 18. Событийная модель коммуникации Backbone.Wreqr Это расширенная версия Backbone.Events. https://github.com/marionettejs/backbone.wreqr v0.2.0 / Forks: 14 / Stars: 126 Состоит из: 1. EventAggregator 2. Commands 3. Request/Response Опыт разработки эффективного SPA, Евгений Абросимов 18
  19. 19. Событийная модель коммуникации Backbone.Wreqr.EventAggregator Аналог Backbone.Events var vent = new Backbone.Wreqr.EventAggregator(); vent.on("foo", function () { console.log("foo event"); }); vent.trigger("foo"); Опыт разработки эффективного SPA, Евгений Абросимов 19
  20. 20. Событийная модель коммуникации Backbone.Wreqr.Commands Это реализация паттерна «Команда» var commands = new Backbone.Wreqr.Commands(); commands.setHandler("foo", function () { console.log("the foo command was executed"); }); commands.execute("foo"); Опыт разработки эффективного SPA, Евгений Абросимов 20
  21. 21. Событийная модель коммуникации Backbone.Wreqr.RequestResponse Реализация паттерна «Запрос/Ответ» var reqres = new Backbone.Wreqr.RequestResponse(); reqres.setHandler("foo", function () { return "foo requested. this is the response"; }); var result = reqres.request("foo"); Опыт разработки эффективного SPA, Евгений Абросимов 21
  22. 22. Манипуляция с DOM Перекомпоновка это процесс реконструкции части дерева DOM, которая была затронута. Причиной для перекомпоновки служит изменении геометрии элемента. Перерисовка это процесс повторного отрисовывания элементов части дерева DOM, которая была затронута. Если при изменении не была затронута геометрия элемента, то выполняется только перерисовка Минимизируйте количество перекомпоновок и перерисовок! Опыт разработки эффективного SPA, Евгений Абросимов 22
  23. 23. Backbone.View var someView = Backbone.View.extend({ initialize: function () { this.model.on('change', this.render, this); }, render: function () { this.$el.html(this.template(this.model.toJSON())); return this; } }); Что здесь неправильно? Опыт разработки эффективного SPA, Евгений Абросимов 23
  24. 24. Backbone.View Сбор данных: two-way data bindings 1. Backbone.modelBinder https://github.com/theironcook/Backbone.ModelBinder v1.0.4 / forks: 154 / stars / 1077 <input type="text" name="address"/> render: function(){ this.$el.html(_.template(this.template, this.model.toJSON())); this.modelBinder.bind(this.model, this.el); } или render: function(){ var bindings = { address: '[name=address]' }; this.$el.html(_.template(this.template, this.model.toJSON())); this.modelBinder.bind(this.model, this.el, bindings); } Опыт разработки эффективного SPA, Евгений Абросимов 24
  25. 25. Backbone.View Сбор данных: two-way data bindings 2. Rivets.js + Adapter http://rivetsjs.com/ v0.5.10 / forks: 96 / stars: 1084 <input type="text" name="address" data-value="p.address" /> <span data-text="p.address"></span> render: function(){ this.$el.html(_.template(this.template, this.model.toJSON())); this.rivets.bind(this.el, {p: this.model}); } Опыт разработки эффективного SPA, Евгений Абросимов 25
  26. 26. Управление памятью Дано: имеем view с несколькими дочерними views. Удаляем родительское view. Вопрос: Что произойдет с дочерними views? Ответ: В ваше приложение придут zombies. Опыт разработки эффективного SPA, Евгений Абросимов 26
  27. 27. Управление памятью Для того, чтобы избежать появления zombies нужно: • перед удалением родительской view, удалять дочерние views; • отписываться от всех хендлеров событий (this.model.off() или использовать this.listenTo(), this.$el.empty()); • уничтожать запущенные виджеты Jquery UI; • никогда не удалять контейнер одной view из другой view. Опыт разработки эффективного SPA, Евгений Абросимов 27
  28. 28. Управление памятью Zombies: Решение var baseView = Backbone.View.extend({ nested: [], initialize: function () { Backbone.View.prototype.initialize.call(this); }, register: function (sub) { if (sub instanceof Backbone.View) { this.nested.push(sub); } }, remove: function () { var viewsCount = this.nested.length; if (viewsCount) { for (var i = 0; i < viewsCount; i++) { this.nested[i].remove(); } } this.$el.empty(); Backbone.View.prototype.remove.call(this); } }); Опыт разработки эффективного SPA, Евгений Абросимов 28
  29. 29. Client vs Server Как сократить время коммуникации клиента и сервера? 1. Отдавать не разметку, а JSON. Разметка формируется на клиенте. 2. Не отправлять серверу лишние запросы. Пул ajax-запросов позволит получить клиенту только актуальные данные. 3. Не спрашивать у сервера то, что уже было получено ранее. Кешируйте то, что уже было получено ранее. Опыт разработки эффективного SPA, Евгений Абросимов 29
  30. 30. Кеширование на клиенте Model и Collection – две сущности, созданные для хранения данных. Model → Запись в таблице БД Collection → Таблица БД Опыт разработки эффективного SPA, Евгений Абросимов 30
  31. 31. Кеширование на клиенте SQL и Backbone.Collection Выборка select * from messages where id = 0 var result = messages.where({ id: 0 }); Вставка insert into messages values ('0', 'Vasya', 'Petya') messages.add(new message({ id: 0, from: 'Vasya', to: 'Petya'})); Удаление delete from messages where id = 1 messages.remove(messages.where({ Id: 1 })) Опыт разработки эффективного SPA, Евгений Абросимов 31
  32. 32. Кеширование на клиенте Репозиторий define(function () { var repository = function() { var tables = { }; function create(name, model) { if (!tables[name]) { tables.push(new Backbone.Collection({ model: model })); } } function insert(name, model) { if (table[name]) { tables[name].add(model); } } function remove(name, options) { if (tables[name]) { tables[name].remove(tables[name].where(options)); } } function select(name, options) { if (tables[name]) { return tables[name].where(options); } return false; } return { create: create, insert: insert, remove: remove, select: select } }; return new repository(); }); Опыт разработки эффективного SPA, Евгений Абросимов 32
  33. 33. Что дальше? Тестирование: TDD & BDD 1. QUnit / v1.12.0 / TDD http://qunitjs.com/ 2. Jasmine / v1.3.1 / BDD http://pivotal.github.io/jasmine/ 3. Mocha / v1.13.0 / BDD & TDD http://visionmedia.github.io/mocha/ Опыт разработки эффективного SPA, Евгений Абросимов 33
  34. 34. Что дальше? Архитектурные фреймворки 1. Marionette / v1.1.0 / forks: 625 / stars: 3729 http://marionettejs.com/ 2. Chaplin / v0.10.0 / forks: 220 / stars: 2321 http://chaplinjs.org 3. Thorax / v2.0.1 / forks: 82 / stars: 865 http://thoraxjs.org/ 4. Giraffe / v0.1.3 / forks: 3 / stars: 66 http://barc.github.io/backbone.giraffe/ Опыт разработки эффективного SPA, Евгений Абросимов 34
  35. 35. Спасибо за внимание Евгений Абросимов ByndyuSoft abrosimov@byndyusoft.com twitter.com/abrosimov Опыт разработки эффективного SPA, Евгений Абросимов 35

×