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

Post on 16-Jun-2015

1.487 views 1 download

Tags:

description

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

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

Опыт разработки

эффективного SPA

Евгений Абросимов

ByndyuSoft

twitter.com/abrosimov

7-я конференция .NET разработчиков

22 сентября 2013

www.dotnetconf.ru

2 Опыт разработки эффективного SPA, Евгений Абросимов

Немного истории

(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);

3 Опыт разработки эффективного SPA, Евгений Абросимов

Немного истории

var $app = $app || {

core: {},

ui: {},

config: {},

utilities: {},

login: {},

registration: {},

//...

};

4 Опыт разработки эффективного SPA, Евгений Абросимов

Что такое SPA?

Single Page Application – это приложение, которое выполняется в браузере. SPA базируется на HTML/JS/CSS/JSON. SPA жестко делит клиентскую и серверную логику. SPA общается с сервером только чистыми данными. Разметка хранится на стороне клиента в шаблонах. Перезагрузки страницы не происходит.

SPA vs MPA

6 Опыт разработки эффективного SPA, Евгений Абросимов

Примеры SPA

7 Опыт разработки эффективного SPA, Евгений Абросимов

Критерии эффективности

1. Модульность системы.

2. Однозначное определение местоположения

пользователя роутом.

3. Событийная модель коммуникации.

4. Минимизированное количество изменений DOM.

5. Отсутствие утечек памяти.

6. Минимизированное количество запросов к серверу.

8 Опыт разработки эффективного SPA, Евгений Абросимов

Фундамент для эффективного SPA

1. Минимальное время для старта SPA. Минимум запросов к серверу за ресурсами: images.png, style.css, script.js.

2. Эффективная верстка. Верстка должна разделять идентификаторы и классы, которые отвечают

за логику работы, и классы, которые отвечают за отображение макета

приложения в браузере. Идеально: логика на id, верстка на class.

Использование быстрых селекторов. Минимизация объема разметки.

3. Хороший Javascript

9 Опыт разработки эффективного SPA, Евгений Абросимов

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

10 Опыт разработки эффективного SPA, Евгений Абросимов

Сущности backbone.js Backbone.Model

1. Model – это единица данных. Отвечает за получение, отправку,

хранение, валидацию и прочие манипуляции с данными какой то

сущности.

var sampleModel = Backbone.Model.extend({ url: '/path/to/data', defaults: { //Значения атрибутов по-умолчанию }, initialize: function () { //Конструктор модели }, someMethod: function () { //Тело метода } });

11 Опыт разработки эффективного SPA, Евгений Абросимов

Сущности 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; }); }, });

12 Опыт разработки эффективного SPA, Евгений Абросимов

Сущности 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; } });

13 Опыт разработки эффективного SPA, Евгений Абросимов

Сущности backbone.js Backbone.Router

4. Router предоставляет методы для маршрутизации на стороне

клиента, а также связывания этих действий с событиями.

var sampleRouter = Backbone.Router.extend({ routes: { //Словарь роутов и экшенов 'index': 'index', 'search/:id': 'search' }, initialize: function () { //Конструктор роута }, index: function () { //Тело метода }, search: function (id) { //Тело метода } });

14 Опыт разработки эффективного SPA, Евгений Абросимов

Модульная структура

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" data-main="app/packages.js"></script>

15 Опыт разработки эффективного SPA, Евгений Абросимов

Модульная структура

или

define('mymodule',['jquery'], function ($) { return { foo: 'bar' }; } );

define('mymodule', function (require) { var $ = require('jquery'); return { foo: 'bar' }; } );

16 Опыт разработки эффективного SPA, Евгений Абросимов

Событийная модель коммуникации

Как обеспечить коммуникацию модулей?

Использовать события!

$('#someElement').on('someEvent', function () { //Тело обработчика }); ... $('#someElement').trigger('someEvent');

Анти-паттерн!

17 Опыт разработки эффективного SPA, Евгений Абросимов

Событийная модель коммуникации Backbone.Events

var vent = _.extend({}, Backbone.Events);

vent.on('smth', function (data) {

console.log(data); //Object {hello: "world"}

});

vent.trigger('smth', { hello: 'world' });

vent.off('smth');

Backbone.Events – это встроенные в backbone объект, который реализует паттерн Наблюдатель (Observer).

18 Опыт разработки эффективного SPA, Евгений Абросимов

Событийная модель коммуникации Backbone.Wreqr

Это расширенная версия Backbone.Events.

https://github.com/marionettejs/backbone.wreqr

v0.2.0 / Forks: 14 / Stars: 126

Состоит из:

1. EventAggregator

2. Commands

3. Request/Response

19 Опыт разработки эффективного SPA, Евгений Абросимов

Событийная модель коммуникации Backbone.Wreqr.EventAggregator

Аналог Backbone.Events

var vent = new Backbone.Wreqr.EventAggregator(); vent.on("foo", function () { console.log("foo event"); }); vent.trigger("foo");

20 Опыт разработки эффективного SPA, Евгений Абросимов

Событийная модель коммуникации Backbone.Wreqr.Commands

Это реализация паттерна «Команда»

var commands = new Backbone.Wreqr.Commands(); commands.setHandler("foo", function () { console.log("the foo command was executed"); }); commands.execute("foo");

21 Опыт разработки эффективного SPA, Евгений Абросимов

Событийная модель коммуникации 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");

22 Опыт разработки эффективного SPA, Евгений Абросимов

Манипуляция с DOM

Перекомпоновка это процесс реконструкции части

дерева DOM, которая была затронута. Причиной для перекомпоновки служит изменении геометрии элемента.

Перерисовка это процесс повторного

отрисовывания элементов части дерева DOM,

которая была затронута. Если при изменении не была затронута геометрия элемента, то выполняется

только перерисовка

Минимизируйте количество перекомпоновок и перерисовок!

23 Опыт разработки эффективного SPA, Евгений Абросимов

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; } });

Что здесь неправильно?

24 Опыт разработки эффективного SPA, Евгений Абросимов

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); }

25 Опыт разработки эффективного SPA, Евгений Абросимов

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}); }

26 Опыт разработки эффективного SPA, Евгений Абросимов

Управление памятью

Дано: имеем view с несколькими дочерними

views. Удаляем родительское view.

Вопрос: Что произойдет с дочерними views?

Ответ: В ваше приложение придут zombies.

27 Опыт разработки эффективного SPA, Евгений Абросимов

Управление памятью

Для того, чтобы избежать появления zombies нужно:

• перед удалением родительской view, удалять

дочерние views;

• отписываться от всех хендлеров событий

(this.model.off() или использовать this.listenTo(),

this.$el.empty());

• уничтожать запущенные виджеты Jquery UI;

• никогда не удалять контейнер одной view из

другой view.

28 Опыт разработки эффективного SPA, Евгений Абросимов

Управление памятью 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); } });

29 Опыт разработки эффективного SPA, Евгений Абросимов

Client vs Server

Как сократить время коммуникации клиента и сервера? 1. Отдавать не разметку, а JSON. Разметка формируется на клиенте.

2. Не отправлять серверу лишние запросы. Пул ajax-запросов позволит получить клиенту только актуальные данные.

3. Не спрашивать у сервера то, что уже было получено ранее. Кешируйте то, что уже было получено ранее.

30 Опыт разработки эффективного SPA, Евгений Абросимов

Кеширование на клиенте

Model и Collection – две сущности,

созданные для хранения данных.

Model → Запись в таблице БД

Collection → Таблица БД

31 Опыт разработки эффективного SPA, Евгений Абросимов

Кеширование на клиенте 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 }))

Выборка

Вставка

Удаление

32 Опыт разработки эффективного SPA, Евгений Абросимов

Кеширование на клиенте Репозиторий

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(); });

33 Опыт разработки эффективного SPA, Евгений Абросимов

Что дальше? Тестирование: 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/

34 Опыт разработки эффективного SPA, Евгений Абросимов

Что дальше? Архитектурные фреймворки

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/

35 Опыт разработки эффективного SPA, Евгений Абросимов

Спасибо за внимание

Евгений Абросимов

ByndyuSoft

abrosimov@byndyusoft.com

twitter.com/abrosimov