~ 2,5 годаFront-end developer
НГС.АвтоНГС.ПогодаНГС.Недвижимость
~ 1 годJavaScript developer
N1.ru
Обо мне
~6 летВелосипедист
~ 20 регионов РФ Объявления по недвижимости
~ 1 годНаходится в разработке
● Динамичный интерфейс Много мелких изменений прямо в браузере
● Быстро выпускать новые фичи Маленькая команда должа работать эффективно
● Поддерживаемость При большом количестве кода на новом уровне
● SEO Индексация поисковыми роботами
Начальные требования
Шаблонизацию и её виды
Клиентскийрендеринг
Серверныйрендеринг
Мы рассмотрим
Шаблонизация
HTML-шаблонизацияМонолитные строки с кодом
DOM-шаблонизацияДинамические элементы документа
Виды шаблонизации
HTML-шаблонизация
HTML-шаблонизаторы
● Handlebars
● Hogan.js
● dust.js
● Mustache.js
И другие
var tpl = Handlebars.compile( '<div>{{name}} <span>{{age}}</span></div>');
var html = tpl({name: 'Василий Николаевич', age: 32});
<div>Василий Николаевич <span>32</span></div>
Пример на Handlebars
Чем круто?
Скорость рендерингаСписок объявлений из 250 элементов за ~ 25ms
ПростотаНикакой “магии”. Задали шаблон, передали данные, получили результат
УниверсальностьМожно использовать как в браузере, таки под node.js
Чем не подходит?
НеповоротливостьОбновлять шаблоны приходится целиком
Сложно в динамикеЧем больше динамических изменений, тем тяжелее использовать
НесамостоятельностьНужны дополнительные инструменты для мелких модификаций
Как нам HTML-шаблонизация?
● Быстро, но неповоротливо Отличная скорость рендеринга, но не предусматривает мелких модификаций
● Требует дополнительных инструментов Нет единой системы контроля за разметкой
● Долго разрабатывать Вся логика изменений должна быть прописана явно и вручную
DOM-шаблонизация
Document Object ModelОбъектная модель документа
DOM-шаблонизаторы
● React
● Angular.js
● Vue.js
● Ractive.js
И другие
var div = document.createElement('div');
var text = document.createTextNode('Василий Николаевич ');
var age = document.createElement('span');
age.innerHTML = 32;
div.appendChild(text)
div.appendChild(age);
[ <div>Василий Николаевич <span>32</span></div> ]
DOM API
jQuery умеет
$('<div>Василий Николаевич <span>32</span></div>');
[ <div>Василий Николаевич <span>32</span></div> ]
Реактивностьvar data = { name: 'Василий Николаевич', age: 32};
> _
<div> Василий Николаевич <span>32<span></div>
Реактивностьvar data = { name: 'Василий Николаевич', age: 32};
data.age = 64;> _
<div> Василий Николаевич <span>64<span></div>
Чем огорчает?
Медленный запуск Первая инициализация может быть медленной
Много разметки - долго Нужно значительное время для обновления больших порций разметки
Чем круто?
Реактивность При обновлении данных автоматически обновляется разметка. Экономит время
СамостоятельностьДостаточно одного инструмента для контроля всей разметки
СкоростьПри мелких обновлениях разметки
Как нам DOM-шаблонизация?
● Уменьшает время выпуска новых фич Реактивность позволяет надёжно контролировать разметку
● Упрощает поддержку За счёт уменьшения количества ручных операций уменьшается код
● Единый инструмент контроля разметки Использовать jQuery и аналоги не обязательно
Итак, шаблонизация
HTML
1
2
3
5
DOM
5
5
5
1
Динамичность
Скрость разработки
Поддерживаемость
SEO
* cубъективная оценка
Выбираем инструментдля рендеринга
Исходные данные
React (v0.13.3)
IE8+
586 kb
118 kb
66 kb
Да
Vue.js (v0.12.7)
IE9+
221 kb
68 kb
22 kb
Нет
Поддержка браузеров
Размер
Размер minified
Размер minified gziped
Серверный рендеринг
Компоненты
Web ComponentsКастомный тег со своим шаблоном, стилями, скриптами
В более широком смыслеСамостоятельный функциональный блокс привязанными разметкой и стилями
var Example = React.createClass({ render: function () { return <div>{this.props.name} <span>{this.props.age}</span></div>; }});
JSX
var Example = React.createClass({ render: function () { return <div>{this.props.name} <span>{this.props.age}</span></div>; }});
JSX
var Example = React.createClass({ render: function () { return (React.createElement('div', null, this.props.name, ' ', React.createElement('span', null, this.props.age) )); }});
var app = React.render( <Example />, document.body);
Запуск приложенияvar Example = React.createClass({ getInitialState: function () { return {name: 'Василий Николаевич', age: 32}; }, render: function () { return <div>{this.state.name} <span>{this.state.age}</span></div>; }});
<body> <div data-reactid=".1"> <span data-reactid=".1.0">Василий Николаевич<span> <span data-reactid=".1.1"> <span> <span data-reactid=".1.2">32<span> </div></body>
Видимая разметка
<body> <div data-reactid=".1"> <span data-reactid=".1.0">Василий Николаевич<span> <span data-reactid=".1.1"> <span> <span data-reactid=".1.2">32<span> </div></body>
Видимая разметка
Virtual DOM Real DOM
PATCH
<body> <div data-reactid=".1"> <span data-reactid=".1.0">Василий Николаевич<span> <span data-reactid=".1.1"> <span> <span data-reactid=".1.2">32<span> </div></body>
Видимая разметка
> _
<body> <div data-reactid=".1"> <span data-reactid=".1.0">Василий Николаевич<span> <span data-reactid=".1.1"> <span> <span data-reactid=".1.2">64<span> </div></body>
Видимая разметка
app.setState({age: 64});> _
Динамические компонентыvar Strict = React.createClass({ render: function () { return <div>{this.props.name} <span>{this.props.age}</span></div>; }});
var Fancy = React.createClass({ render: function () { return (<div> Меня зовут {this.props.name} и мне сегодня <span>{this.props.age}</span> года </div>); }});
Динамические компонентыvar Example = React.createClass({ ... });
getInitialState: function () { return {name: 'Василий Николаевич', age: 32, view: 'strict'};}
switchView: function () { if (this.state.view === 'strict') { this.setState({'view': 'fancy'}); } else { this.setState({'view': 'strict'}); }}
Динамические компонентыrender: function () { var view; if (this.state.view === 'strict') { view = <Strict name={this.state.name} age={this.state.age} />; } if (this.state.view === 'fancy') { view = <Fancy name={this.state.name} age={this.state.age} />; }
return <div onClick={this.switchView}>{view}</div>;}
Динамические компоненты
Василий Николаевич 32
Меня зовут Василий Николаевич и мне сегодня 32 года
Запуск приложения
var Example = { el: 'body', data: { name: 'Василий Николаевич', age: 32 }};
var app = new Vue(Example);
<body><div>{{name}} <span>{{age}}<span></div></body>
<body> <div> Василий Николаевич <span>32<span> </div></body>
Видимая разметка
> _
<body> <div> Василий Николаевич <span>64<span> </div></body>
Видимая разметка
app.age = 64;> _
Динамические компонентыvar Strict = { props: ['name', 'age'], template: '<div>{{name}} <span>{{age}}</span></div>'};
var Fancy = { props: ['name', 'age'], template: '<div>' + 'Меня зовут {{name}} и мне сегодня <span>{{age}}</span> года' + '</div>'};
Динамические компоненты
data: { name: 'Василий Николаевич', age: 32, view: 'strict'}
components: {strict: Strict, fancy: Fancy}
var Example = { ... };
methods: { switchView: function () { if (this.view === 'strict') { this.view = 'fancy'; } else { this.view = 'strict'; } }}
Динамические компоненты<div v-on="click: switchView"> <div v-component="{{view}}" name="{{name}}" age="{{age}}"></div></div>
Динамические компоненты
Василий Николаевич 32
Меня зовут Василий Николаевич и мне сегодня 32 года
Пример: сила Vue.js
Один компонент Динамическая модель страницы
Связь между компонентами
http://n.gs/vue
Оценим “на глазок”
● Vue.js – ещё меньше кода В основе философии лежит простота и минимализм
● Vue.js – ещё проще работа с данными Использование нативных геттеров/сеттеров позволяет менять данные без вызова дополнительных функций
● Vue.js – динамичность ещё изящней Система динамических компонентов позволяет просто и понятно их переключать, отделять шаблоны от скриптов “из коробки”
Производительность: Браузер
Отрендерим список объявлений● 50 элементов
● 250 элементов
Core i3 @ 3.40GHz; Ubuntu 14.04
Рендеринг страницы
React
580 ms
1832 ms
Vue.js
302 ms
730 ms
50 объявлений
250 объявлений
* среднее время за 100 замеров
Добавление 1 элемента
React
175 ms
830 ms
Vue.js
12 ms
16 ms
50 объявлений
250 объявлений
* среднее время за 100 замеров
PureRenderMixin
● Использует shouldComponentUpdate Проверяет изменились ли данные и нужно ли запускать render
● Для компонентов с простыми данными Не может отследить изменения объектов
● Может значительно ускорить рендеринг Благодаря исключению вызовов render у неизменившихся компонентов
Добавление 1 элемента с PRM
React
12 ms
16 ms
Vue.js
12 ms
16 ms
50 объявлений
250 объявлений
* среднее время за 100 замеров
Полное обновление списка
React
232 ms
685 ms
Vue.js
238 ms
670 ms
50 объявлений
250 объявлений
* среднее время за 100 замеров
Производительность: Сервер
Окружение
● io.js v2.40 Для запуска тестов
● Express v4.13.1 Для вывода в браузер
● Jsdom v5.6.1 Для эмуляции документа на сервере
Что будем тестировать
● React.renderToString() Время исполнения
● React.renderToStaticMarkup() Время исполнения
● Vue.js под jsdom От запуска jsdom до исполнения new Vue()
Рендеринг списка из 250 элементов
Время
5202 ms
Размер страницы
1.5 MBReact.renderToString()
* среднее время за 100 замеров
Рендеринг списка из 250 элементов
Время
5202 ms
4883 ms
Размер страницы
1.5 MB
0.8 MB
React.renderToString()
React.renderToStaticMarkup()
* среднее время за 100 замеров
Рендеринг списка из 250 элементов
Время
5202 ms
4883 ms
5854 ms
Размер страницы
1.5 MB
0.8 MB
0.8 MB
React.renderToString()
React.renderToStaticMarkup()
Vue.js + jsdom
* среднее время за 100 замеров
React (node)
1250 msВремя
по данным http://www.slideshare.net/nickdreckshage/react-meetup
React* (node)
650 ms
Hogan (node)
450 ms
Mustache (go)
30 ms
* используя best practices
Сторонняя оценка
VueServer.js
Повторяет результат Vue.js
Без эмуляции DOM Асинхронный
Рендеринг списка из 250 элементов
Время
5202 ms
4883 ms
5854 ms
166 ms
Размер страницы
1.5 MB
0.8 MB
0.8 MB
0.8 MB
React.renderToString()
React.renderToStaticMarkup()
Vue.js + jsdom
VueServer.js
* среднее время за 100 замеров
Подведём итог
Производительность
React
1832 ms
16 ms
685 ms
4883 ms
Vue.js
730 ms
16 ms
670 ms
5854 ms / 166 ms*
Рендеринг FE
Добавление 1 элемента
Замена списка целиком
Рендеринг BE
* c использованием VueServer.js
Итоговая оценка по требованиям
React
4
3
5
1
Vue.js
5
5
5
1 / 5*
Динамичность
Скрость разработки
Поддерживаемость
SEO
cубъективная оценка
* c использованием VueServer.js
Спасибо за внимание!Вопросы?
Андрей СолодовниковJS-разработчик НГС[email protected]
● http://n.gs/vue Пример на Vue.js с QR-кода
● http://n.gs/perf Тесты производительности