Рендеринг может
больше:
Vue.js vs React
Андрей Солодовников
a.solodovnikov@office.ngs.ru
~ 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-разработчик НГС
a.solodovnikov@office.ngs.ru
●
http://n.gs/vue
Пример на Vue.js с QR-кода
●
http://n.gs/perf
Тесты производительности

Рендеринг может больше: vue.js vs React, Андрей Солодовников