Изоморфные React-приложения производительность и...

Preview:

Citation preview

Изоморфные React-приложения:производительность и масштабированиеДенис Измайлов

Почему от классическогоSingle Page Application

необходимо отказаться?

Как изоморфные приложенияотразятся на Вашей зарплате?

Что вы будете делатьна этих выходных?

Идеально1. React 142. webpack3. ES64. Node.js5. Express / koa6. Isomorphic (Universal) apps

Часть 1

Web стал оченьбольшим

Искусство

Разработка под Web

Наука

Раньше было просто• Создал страницу• Добавил пару скриптов• Отправил в Production

Раньше было просто

Сервер

Браузер

Раньше было просто

Сервер

Браузер

Делал всё

Раньше было просто

Сервер

Браузер- HTML- [CSS, JavaScript]

Делал всё

Это работало

Single PageApplications

(SPA)

Single Page Application

Сервер

Браузер

Single Page Application

Сервер

Браузер

Страница существует?Авторизация нужна?Доступ есть?

Single Page Application

Сервер

Браузер

Страница существует?Авторизация нужна?Доступ есть?

- Tiny HTML, [CSS]- JavaScript bundle

Single Page ApplicationПлюсы• Легко начать

• webpack• <div id=“root” />• React, Redux• build

Single Page ApplicationПлюсы• Легко начать

• Богатый функционалwebpack, <div id=“root” />, React, Redux

Single Page ApplicationПлюсы• Легко начать

• Богатый функционал• Быстро дорабатывать

webpack, <div id=“root” />, React, Redux

Single Page ApplicationПлюсы• Легко начать

• Богатый функционал• Быстро дорабатывать• Отзывчивый UI

webpack, <div id=“root” />, React, Redux

Single Page ApplicationПлюсы• Легко начать

• Богатый функционал• Быстро дорабатывать• Отзывчивый UI• Удобно кэшировать

webpack, <div id=“root” />, React, Redux

- Wow. И не одного минуса?

Single Page ApplicationМинусы• Долгая загрузка

• JavaScript bundle up to 3-5 Mb • первое обращение• исполнение• память

Single Page ApplicationМинусы• Долгая загрузка

• Сложность поддержки• side-эффекты• memory leak

1st request, CPU, mem

Single Page ApplicationМинусы• Долгая загрузка

• Сложность поддержки

• Пустая страница, один URL

1st request, CPU, mem

side-эффекты, memory leaks

Single Page ApplicationМинусы• Долгая загрузка

• Сложность поддержки

• Пустая страница, один URL• Legacy Browsers

1st request, CPU, mem

side-эффекты, memory leaks

- Разве это минусы?

Single Page ApplicationМинусы• Долгая загрузка

для бизнеса

снижение UX

Single Page ApplicationМинусы• Долгая загрузка• Сложность поддержки

для бизнеса

снижение UXриски

Single Page ApplicationМинусы• Долгая загрузка• Сложность поддержки• Пустая страница

для бизнеса

снижение UXриски

проблемы SEO

Single Page ApplicationМинусы• Долгая загрузка• Сложность поддержки• Пустая страница• Один URL

для бизнеса

снижение UXриски

проблемы SEOпроблемы SMM

Single Page ApplicationМинусы• Долгая загрузка• Сложность поддержки• Пустая страница• Один URL• Legacy Browsers

для бизнеса

снижение UXриски

проблемы SEOпроблемы SMM

потеря ЦА

Single Page ApplicationМинусы• Долгая загрузка• Сложность поддержки• Пустая страница• Один URL• Legacy Browsers

для бизнеса

снижение UXриски

проблемы SEOпроблемы SMM

потеря ЦА

Расходы

Single Page ApplicationМинусы

для бизнеса

снижение UXриски

проблемы SEOпроблемы SMM

потеря ЦА

Расходы

- WAT? Что делать?

Взять лучшее из обоих миров

Изоморфныеприложения

Изоморфные приложения

By isomorphic we mean that any given line of code (with notable exceptions) can execute both on the client and the server.

Charlie Robbins,18 Oct 2011

ШаблоныСтилиЛокализацияКонфигурацияRoutes

Права доступаМоделиСхемыВалидацияСервисы

Изоморфные приложения

server.jsNode.js

worker.js

client.jsBrowser

admin.js

Бизнес-логикаКомпонентыAPI-интерфейсыActions, ReducersStatic Files

Браузер

Изоморфные приложения

Front-endсервер

Back-endсервер

DatabaseJavaetc

Браузер

Изоморфные приложения

Front-endсервер

Back-endсервер

DatabaseJavaetc

Браузер

Изоморфные приложения

Front-endсервер

Back-endсервер

DatabaseJavaetc

- HTML- [critical CSS]- …

Front-endклиент

Изоморфные приложения

Front-endсервер

Back-endсервер

DatabaseJavaetc

- HTML- [critical CSS]- JS Bundle

Front-endклиент

Изоморфные приложения

Front-endсервер

Back-endсервер

DatabaseJavaetc

- HTML- [critical CSS]- JS Bundle

Front-endклиент

Изоморфные приложения

Front-endсервер

• Единая среда исполнения

• Общая кодовая база

• Полный контроль

• Экосистема

- Но как?

Server-Side Rendering(SSR)

Server-Side Rendering• Сборка React-приложения в HTML-

код на Front-end сервере• Моментальное отображение в

браузере, ещё до загрузки JS• Когда JS загрузится, React только

добавит обработчики событий• А это очень быстро

Server-Side RenderingКод на сервере выглядит очень просто:

import ReactDOMServer from 'react-dom/server';import Application from './components/application';

const body = ReactDOMServer.renderToString( <Application />);

Server-Side Rendering1. Пользователь видит страницу

мгновенно2. Отсутствие дополнительных запросов

на получение данных3. Страница может работать даже без JS4. Полноценная URL-навигация и мета-

тэги5. Сохранение всех возможностей

современного JavaScript

Часть 2

Производительностьи масштабирование

Масштабирование

Масштабированиефункциональное

Server-Side RenderingВсё супер, когда данные есть:import ReactDOMServer from 'react-dom/server';import Application from './components/application';

const initialState = { siteName: 'HighLoad++ 2015' };const body = ReactDOMServer.renderToString( <Application state={initialState} />);

Server-Side RenderingВсё супер, когда данные есть:import ReactDOMServer from 'react-dom/server';import Application from './components/application';

const initialState = { siteName: 'HighLoad++ 2015' };const body = ReactDOMServer.renderToString( <Application state={initialState} />);

Но если их надо получать извне?

Server-Side RenderingКак получить асинхронный State:

1. Вручную для каждой страницы2. Facebook Relay3. redux-catch-promise

Асинхронный StateВручную для каждой страницы:

• Получить State, необходимый для страницы

• ReactDOMServer.renderToString()

Асинхронный StateFacebook Relay:1. The framework for building data-

driven React applications2. Declarative. Colocation. Mutations.3. https://github.com/facebook/relay/issu

es/1364. 1Q2016

Асинхронный Stateredux-catch-promise:• Redux - state container для React• Redux: the best for isomorphic apps,

MoscowJS 25https://youtu.be/Uyk_8WWna6s

• redux-catch-promise - это middleware для Redux

Асинхронный Stateredux-catch-promise:1. Вешаем callback для захвата Promise-

экшнов2. Делаем рендер приложения3. Делаем запрос к БД, диспатчим Promise4. После рендера - имеем все эти

промисы, ожидаем их завершения5. Повторный рендер, с данными

Асинхронный Stateredux-catch-promise:1. Примеры и исходный код:

https://github.com/DenisIzmaylov/redux-catch-promise

2. Установка:npm install redux-catch-promise

Производительность

Производительность

Тестовый стенд:

MacBook Pro 15” Retina (Early 2013)2.4 GHz Intel Core i7

ПроизводительностьРазмер страницы: 56 238 байт

ПроизводительностьРазмер страницы: 56 238 байт

ПроизводительностьРазмер страницы: 56 238 байт

ПроизводительностьРазмер страницы: 56 238 байт

ПроизводительностьРазмер страницы: 56 238 байт

ПроизводительностьРазмер страницы: 56 238 байт

Производительность

Для теста используем:ab -n 100 http://localhost:3000/profile

Производительность

Для теста используем:ab -n 100 http://localhost:3000/profile

Запускаем…

Производительность

Для теста используем:ab -n 100 http://localhost:3000/profile

Запускаем…Time per request: 61.850 ms

Производительность

61.850 ms

Это много или мало?

Производительность

61.850 ms

Тот же шаблон в Handlebars:

8.385 ms

86% less

Производительность1. Идём в Google - ничего полезного.2. Пробуем спросить Twitter - тишина:

Производительность

Ок, а что если?NODE_ENV=production

Запускаем…

Производительность

Ок, а что если?NODE_ENV=production

Запускаем…Time per request: 37.943 ms

(vs 61.850 ms)39% less

Производительность

Вроде лучше.

Производительность

Вроде лучше.

Но всё ещё не торт.

Ищем дальше

GitHub issues

Производительность• “Server rendering is slower with npm

react”

https://github.com/facebook/react/issues/812

Производительность• “Server rendering is slower with npm

react”

https://github.com/facebook/react/issues/812

Решение:явно подключать react/dist/react.min.js

ПроизводительностьСоздаём node_modules/react.js:

if (process.env.NODE_ENV === 'production') {module.exports =

require('react/dist/react.min.js');} else { module.exports = require('react/dist/react.js');}

ПроизводительностьСоздаём node_modules/react.js:

if (process.env.NODE_ENV === 'production') {module.exports =

require('react/dist/react.min.js');} else { module.exports = require('react/dist/react.js');}

Как это изменило результат?

Производительность

Server rendering is slower with npm react

react/dist/react.min.js

Запускаем…

Производительность

Server rendering is slower with npm reactreact/dist/react.min.js

Запускаем…Time per request: 38.253 ms

(vs 37.943 ms)0.08% more

Производительность

Server rendering is slower with npm reactreact/dist/react.min.js

Запускаем…Time per request: 38.253 ms

(vs 37.943 ms)0.08% more

Series10

17.5

35

52.5

7062

8

38 38

React SSR Handlebars production react.js.min

Результаты

Series10

17.5

35

52.5

7062

8

38 38

React SSR Handlebars production react.js.min

Результаты39% less

Часть 3

Продвинутые решения

Продвинутые решения

1.Precompilation + Cache2.Rendering Separation3.React DOM Stream 4.Facebook BigPipe 5.HAProxy

Precompilation + Cache• UI = f(state)• f = React Component• state = path + ...

Простое решение: redisFirst render: redis + kue + workers

Rendering Separation

React DOM Stream• Flushing the Document Early• “Streams make this library as much as

47% faster in sending down a full page than ReactDOM.renderToString, and user perceived performance gains can be even greater.”

• Target - 108KB page on Heroku• Time To First Byte (TTFB) - 65% less• Time To Last Byte (TTLB) - 37% less• https://github.com/aickin/react-dom-strea

m

Facebook BigPipe• Сборка страницы в процессе загрузки• Загружается параллельно• Устойчивость к ошибкам

Facebook BigPipe• Сборка страницы на в процессе загрузки• Всё, что необходимо - загружается параллельно• Устойчивость к ошибкам

Facebook BigPipe

HAProxy• Обратитесь к DevOps• Несколько экземпляров

Заключение

Полезные материалы1. Supercharging page load (100 Days of Google

Dev) https://youtu.be/d5_6yHixpsQ2. Making Netflix.com Faster

http://techblog.netflix.com/2015/08/making-netflixcom-faster.html

3. New technologies for the new LinkedIn home page https://engineering.linkedin.com/frontend/new-technologies-new-linkedin-home-page

4. Improving performance on Twitter.com https://blog.twitter.com/2012/improving-performance-on-twittercom

5. Scaling Isomorphic Javascript Code http://blog.nodejitsu.com/scaling-isomorphic-javascript-code/

Полезные материалы6. From AngularJS to React: The Isomorphic Way

https://blog.risingstack.com/from-angularjs-to-react-the-isomorphic-way/

7. Isomorphic JavaScript: The Future of Web Apps http://nerds.airbnb.com/isomorphic-javascript-future-web-apps/

8. React server side rendering performance http://www.slideshare.net/nickdreckshage/react-meetup

9. The Lost Art of Progressive HTML Rendering http://blog.codinghorror.com/the-lost-art-of-progressive-html-rendering/

Рекомендации• Присоединяйтесь

к сообществу MoscowJShttp://moscowjs.ru/

• Улучшайте английский, не читайте советских газет

• Читайте оригиналы и технические блоги

• Активно внедряйте в свою жизнь Twitter и GitHub

Послесловие«Большинство проблем

алгоритмов можно решить сменой структуры

данных», Андрей Ситник

“Changes is our work”,Jake Archibald, Google

Почему от классическогоSingle Page Application

необходимо отказаться?

Спасибо за вниманиеДенис Измайлов

@DenisIzmaylov

https://github.com/DenisIzmaylovhttps://fb.com/denis.izmaylov

Приложение 1

Recommended