ݺߣ

ݺߣShare a Scribd company logo
Functional Reactive Programming
:
Делаем жизнь проще
Parcsis
MoscowJS Meetup 19
Trdat
Mkrtchyan
2
Часть I :
( Функциональная )
3
3
4
( Плюсы (
( Иммутабельные данные )
( Отсутствие состояния )
( Лень, как стратегия вычислений )
( Частичное применение и карринг ))
Получаем декларативный подход
5
( Минусы (
( Производительность )
( Комьюнити слишком маленькое )
( Состояние есть, но оно скрыто ))
6
Часть II :
( Реактивная )
7
reactivemanifesto.org
● Responsive
● Scalable
● Resilient
● Event-driven
8
reactivemanifesto.org
● Responsive
● Scalable
● Resilient
● Event-driven
9
асинхронность
+
дерево состояний
↓
непредсказуемость
10
11
Callback hell
12
arr = [1, 2, 3, 4]
.map(square)
.filter(moreThan3LessThan10)
.reduce(add)
13
FRP >= FP
Источник данных – это поток событий
14
FRP > FP
15
Часть III :
( Программирование )
16
( RxJS ( Microsoft Reactive Extensions )
github.com/Reactive-Extensions/RxJS )
● Большое комьюнити
● Подробная документация
17
( Bacon ( Juha Paananen @raimohanska )
github.com/baconjs/baconjs )
● Простое API
● Ясная документация
18
( Kefir ( Roman Pominov @rpominov )
github.com/pozadi/kefir )
● Высокая производительность
● Активно развивается
19
( Warden.js ( Trdat Mkrtchyan @zeffirsky )
github.com/zefirka/Warden.js )
( ProAct ( Nickolay Tzvetinov @ntzvetinov )
github.com/proactjs/proactjs )
20
var timer;
input.addEventListener('keydown', function(event){
if(event.keyCode == 13){
clearTimeout(timer);
timer = setTimeout(function(){
doSomething();
}, 500);
}
});
Debounce в императивном варианте
21
Bacon.fromEventTarget(input, 'keydown')
.filter(function(event){
return event.keyCode == 13
})
.debounce(500)
.onValue(doSomething);
Debounce в FRP
22
События
var clicks = Bacon.fromBinder(function(sink) {
document.addEventListener('click', sink);
});
Ответы сервера
var responses = Bacon.fromBinder(function(sink) {
$.get('path/to', sink);
});
Таймер
var ticks = Bacon.fromBinder(function(sink) {
setInterval(sink, 1000);
});
Все что угодно – это stream
22
23
События
var clicks = Bacon.fromBinder(function(sink) {
document.addEventListener('click', sink);
});
Ответы сервера
var responses = Bacon.fromBinder(function(sink) {
$.get('path/to', sink);
});
Таймер
var ticks = Bacon.fromBinder(function(sink) {
setInterval(sink, 1000);
});
Все что угодно – это stream
23
24
События
var clicks = Bacon.fromBinder(function(sink) {
document.addEventListener('click', sink);
});
Ответы сервера
var responses = Bacon.fromBinder(function(sink) {
$.get('path/to', sink);
});
Таймер
var ticks = Bacon.fromBinder(function(sink) {
setInterval(sink, 1000);
});
Все что угодно – это stream
24
25
// пусть получаем данные из сокета в форме
// {player : [Object] , score : [Integer] }
var totalScore = 0;
function calculateScore(data){
if(data.player.status == 'A'){
totalScore += data.score
}
}
socket.on('score', calculateScore);
Вычисления в императивном стиле
26
var totalScore = socket.stream('score')
.filter(function (data){
return data.player.status == 'A';
})
.map('.score')
.reduce(function (sum, score){
return sum + score;
})
FRP упрощает вычисления
+ Вычисления не производятся, если они не нужны
+ Состояние чистое
+ Можно переиспользовать функции-обработчики
27
( Интеграция )
28
( Angular )
29
Controller
app.controller('someCtrl', function ($scope, frp){
$scope.users = [];
$scope.query = '';
frp.toStream($scope, 'query')
.debounce(500)
.map('.newResult') // привет $watch
.filter(notEmpty)
.onValue(function(query){
frp.http.get('search:users', { query: query })
.assign($scope, 'users');
});
}
+ В духе Angular
- Вынуждены оборачивать службы Angular в FRP
30
Controller
app.controller('someCtrl', function ($scope, frp){
$scope.users = [];
$scope.query = '';
frp.toStream($scope, 'query')
.debounce(500)
.map('.newResult') // привет $watch
.filter(notEmpty)
.onValue(function(query){
frp.http.get('search:users', { query: query })
.assign($scope, 'users');
});
}
+ Никаких ng-change в разметке
- Неявные $watch и $apply
31
32
( Чуть больше магии, но видно,
как это работает )
( Все побочные действия – это setState )
( Отлично встраивается во FLUX )
( React )
32
33
( React )
componentDidMount: function(){
this.streamFrom(document, 'mousemove')
.map(function(event){
return {
x: event.clientX,
y: event.clientY
}
})
.onValue(this.setState.bind(this));
},
render: function() {
return <h1> X: {this.state.x}, Y: {this.state.y}</h1>
}
34
И это только начало
35
Trdat Mkrtchyan
Twitter: @zeffirsky
Github: zefirka
MoscowJS Meetup 19 (26. 02. 2015)
Ad

Recommended

Solit 2014, Реактивный Javascript. Победа над асинхронностью и вложенностью, ...
Solit 2014, Реактивный Javascript. Победа над асинхронностью и вложенностью, ...
solit
Что API Карт забыл на сервере — Антон Корзунов
Что API Карт забыл на сервере — Антон Корзунов
Yandex
ObjectManager, или как работать с большим количеством объектов на карте, Мари...
ObjectManager, или как работать с большим количеством объектов на карте, Мари...
Ontico
Правильная организация клиент-карточного взаимодействия — Антон Корзунов
Правильная организация клиент-карточного взаимодействия — Антон Корзунов
Yandex
Михаил Давыдов — JavaScript: Асинхронность
Михаил Давыдов — JavaScript: Асинхронность
Yandex
Векторизация кода (семинар 2)
Векторизация кода (семинар 2)
Mikhail Kurnosov
Progr labrab-4-2013-c++
Progr labrab-4-2013-c++
Moscow Aviation Institute (National Research University), MAI
«Опыт использования каналов в корутинах в боевом проекте» Григорий Федоров
«Опыт использования каналов в корутинах в боевом проекте» Григорий Федоров
Mail.ru Group
"Пиринговый веб на JavaScript"
"Пиринговый веб на JavaScript"
FDConf
Лекция 2: Абстрактные типы данных. Алгоритмы сортировки
Лекция 2: Абстрактные типы данных. Алгоритмы сортировки
Mikhail Kurnosov
Groovy и Grails. Быстро и обо всём
Groovy и Grails. Быстро и обо всём
Ruslan Balkin
DSLs in Lisp and Clojure
DSLs in Lisp and Clojure
Vasil Remeniuk
ReactiveUI: Rx + MVVM
ReactiveUI: Rx + MVVM
Stas Shusha
"Observable и Computed на пример KnockoutJS", Ольга Кобец, MoscowJS 29
"Observable и Computed на пример KnockoutJS", Ольга Кобец, MoscowJS 29
MoscowJS
Знакомство с Papervision3d
Знакомство с Papervision3d
Igor Ruzanov
Векторизация кода (семинар 3)
Векторизация кода (семинар 3)
Mikhail Kurnosov
msumobi2. Лекция 2
msumobi2. Лекция 2
Глеб Тарасов
ES2015+: давно пора!
ES2015+: давно пора!
Vitebsk Miniq
Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10
Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10
Mikhail Kurnosov
Александр Русаков - TypeScript 2 in action
Александр Русаков - TypeScript 2 in action
MoscowJS
Виктор Розаев - Как не сломать обратную совместимость в Public API
Виктор Розаев - Как не сломать обратную совместимость в Public API
MoscowJS
Favicon на стероидах
Favicon на стероидах
MoscowJS
E2E-тестирование мобильных приложений
E2E-тестирование мобильных приложений
MoscowJS
Reliable DOM testing with browser-monkey
Reliable DOM testing with browser-monkey
MoscowJS
Basis.js - Production Ready SPA Framework
Basis.js - Production Ready SPA Framework
MoscowJS
Контекст в React, Николай Надоричев, MoscowJS 31
Контекст в React, Николай Надоричев, MoscowJS 31
MoscowJS
Верстка Canvas, Алексей Охрименко, MoscowJS 31
Верстка Canvas, Алексей Охрименко, MoscowJS 31
MoscowJS
Веб без интернет соединения, Михаил Дунаев, MoscowJS 31
Веб без интернет соединения, Михаил Дунаев, MoscowJS 31
MoscowJS
Angular2 Change Detection, Тимофей Яценко, MoscowJS 31
Angular2 Change Detection, Тимофей Яценко, MoscowJS 31
MoscowJS
Создание WYSIWIG-редакторов для веба, Егор Яковишен, Setka, MoscowJs 33
Создание WYSIWIG-редакторов для веба, Егор Яковишен, Setka, MoscowJs 33
MoscowJS

More Related Content

What's hot (11)

"Пиринговый веб на JavaScript"
"Пиринговый веб на JavaScript"
FDConf
Лекция 2: Абстрактные типы данных. Алгоритмы сортировки
Лекция 2: Абстрактные типы данных. Алгоритмы сортировки
Mikhail Kurnosov
Groovy и Grails. Быстро и обо всём
Groovy и Grails. Быстро и обо всём
Ruslan Balkin
DSLs in Lisp and Clojure
DSLs in Lisp and Clojure
Vasil Remeniuk
ReactiveUI: Rx + MVVM
ReactiveUI: Rx + MVVM
Stas Shusha
"Observable и Computed на пример KnockoutJS", Ольга Кобец, MoscowJS 29
"Observable и Computed на пример KnockoutJS", Ольга Кобец, MoscowJS 29
MoscowJS
Знакомство с Papervision3d
Знакомство с Papervision3d
Igor Ruzanov
Векторизация кода (семинар 3)
Векторизация кода (семинар 3)
Mikhail Kurnosov
msumobi2. Лекция 2
msumobi2. Лекция 2
Глеб Тарасов
ES2015+: давно пора!
ES2015+: давно пора!
Vitebsk Miniq
Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10
Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10
Mikhail Kurnosov
"Пиринговый веб на JavaScript"
"Пиринговый веб на JavaScript"
FDConf
Лекция 2: Абстрактные типы данных. Алгоритмы сортировки
Лекция 2: Абстрактные типы данных. Алгоритмы сортировки
Mikhail Kurnosov
Groovy и Grails. Быстро и обо всём
Groovy и Grails. Быстро и обо всём
Ruslan Balkin
"Observable и Computed на пример KnockoutJS", Ольга Кобец, MoscowJS 29
"Observable и Computed на пример KnockoutJS", Ольга Кобец, MoscowJS 29
MoscowJS
Знакомство с Papervision3d
Знакомство с Papervision3d
Igor Ruzanov
Векторизация кода (семинар 3)
Векторизация кода (семинар 3)
Mikhail Kurnosov
ES2015+: давно пора!
ES2015+: давно пора!
Vitebsk Miniq
Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10
Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10
Mikhail Kurnosov

More from MoscowJS (20)

Александр Русаков - TypeScript 2 in action
Александр Русаков - TypeScript 2 in action
MoscowJS
Виктор Розаев - Как не сломать обратную совместимость в Public API
Виктор Розаев - Как не сломать обратную совместимость в Public API
MoscowJS
Favicon на стероидах
Favicon на стероидах
MoscowJS
E2E-тестирование мобильных приложений
E2E-тестирование мобильных приложений
MoscowJS
Reliable DOM testing with browser-monkey
Reliable DOM testing with browser-monkey
MoscowJS
Basis.js - Production Ready SPA Framework
Basis.js - Production Ready SPA Framework
MoscowJS
Контекст в React, Николай Надоричев, MoscowJS 31
Контекст в React, Николай Надоричев, MoscowJS 31
MoscowJS
Верстка Canvas, Алексей Охрименко, MoscowJS 31
Верстка Canvas, Алексей Охрименко, MoscowJS 31
MoscowJS
Веб без интернет соединения, Михаил Дунаев, MoscowJS 31
Веб без интернет соединения, Михаил Дунаев, MoscowJS 31
MoscowJS
Angular2 Change Detection, Тимофей Яценко, MoscowJS 31
Angular2 Change Detection, Тимофей Яценко, MoscowJS 31
MoscowJS
Создание WYSIWIG-редакторов для веба, Егор Яковишен, Setka, MoscowJs 33
Создание WYSIWIG-редакторов для веба, Егор Яковишен, Setka, MoscowJs 33
MoscowJS
Предсказуемый Viewport, Вопиловский Константин, KamaGames Studio, MoscowJs 33
Предсказуемый Viewport, Вопиловский Константин, KamaGames Studio, MoscowJs 33
MoscowJS
Promise me an Image... Антон Корзунов, Яндекс, MoscowJs 33
Promise me an Image... Антон Корзунов, Яндекс, MoscowJs 33
MoscowJS
Регрессионное тестирование на lenta.ru, Кондратенко Павел, Rambler&Co, Moscow...
Регрессионное тестирование на lenta.ru, Кондратенко Павел, Rambler&Co, Moscow...
MoscowJS
"Опыт разработки универсальной библиотеки визуальных компонентов в HeadHunter...
"Опыт разработки универсальной библиотеки визуальных компонентов в HeadHunter...
MoscowJS
"Во все тяжкие с responsive images", Павел Померанцев, MoscowJS 29
"Во все тяжкие с responsive images", Павел Померанцев, MoscowJS 29
MoscowJS
"AMP - технология на три буквы", Макс Фролов, MoscowJS 29
"AMP - технология на три буквы", Макс Фролов, MoscowJS 29
MoscowJS
«Пиринговый веб на JavaScript», Денис Глазков, MoscowJS 28
«Пиринговый веб на JavaScript», Денис Глазков, MoscowJS 28
MoscowJS
"Доклад не про React", Антон Виноградов, MoscowJS 27
"Доклад не про React", Антон Виноградов, MoscowJS 27
MoscowJS
"Web Audio Api", Анатолий Найда, MoscowJS 27
"Web Audio Api", Анатолий Найда, MoscowJS 27
MoscowJS
Александр Русаков - TypeScript 2 in action
Александр Русаков - TypeScript 2 in action
MoscowJS
Виктор Розаев - Как не сломать обратную совместимость в Public API
Виктор Розаев - Как не сломать обратную совместимость в Public API
MoscowJS
Favicon на стероидах
Favicon на стероидах
MoscowJS
E2E-тестирование мобильных приложений
E2E-тестирование мобильных приложений
MoscowJS
Reliable DOM testing with browser-monkey
Reliable DOM testing with browser-monkey
MoscowJS
Basis.js - Production Ready SPA Framework
Basis.js - Production Ready SPA Framework
MoscowJS
Контекст в React, Николай Надоричев, MoscowJS 31
Контекст в React, Николай Надоричев, MoscowJS 31
MoscowJS
Верстка Canvas, Алексей Охрименко, MoscowJS 31
Верстка Canvas, Алексей Охрименко, MoscowJS 31
MoscowJS
Веб без интернет соединения, Михаил Дунаев, MoscowJS 31
Веб без интернет соединения, Михаил Дунаев, MoscowJS 31
MoscowJS
Angular2 Change Detection, Тимофей Яценко, MoscowJS 31
Angular2 Change Detection, Тимофей Яценко, MoscowJS 31
MoscowJS
Создание WYSIWIG-редакторов для веба, Егор Яковишен, Setka, MoscowJs 33
Создание WYSIWIG-редакторов для веба, Егор Яковишен, Setka, MoscowJs 33
MoscowJS
Предсказуемый Viewport, Вопиловский Константин, KamaGames Studio, MoscowJs 33
Предсказуемый Viewport, Вопиловский Константин, KamaGames Studio, MoscowJs 33
MoscowJS
Promise me an Image... Антон Корзунов, Яндекс, MoscowJs 33
Promise me an Image... Антон Корзунов, Яндекс, MoscowJs 33
MoscowJS
Регрессионное тестирование на lenta.ru, Кондратенко Павел, Rambler&Co, Moscow...
Регрессионное тестирование на lenta.ru, Кондратенко Павел, Rambler&Co, Moscow...
MoscowJS
"Опыт разработки универсальной библиотеки визуальных компонентов в HeadHunter...
"Опыт разработки универсальной библиотеки визуальных компонентов в HeadHunter...
MoscowJS
"Во все тяжкие с responsive images", Павел Померанцев, MoscowJS 29
"Во все тяжкие с responsive images", Павел Померанцев, MoscowJS 29
MoscowJS
"AMP - технология на три буквы", Макс Фролов, MoscowJS 29
"AMP - технология на три буквы", Макс Фролов, MoscowJS 29
MoscowJS
«Пиринговый веб на JavaScript», Денис Глазков, MoscowJS 28
«Пиринговый веб на JavaScript», Денис Глазков, MoscowJS 28
MoscowJS
"Доклад не про React", Антон Виноградов, MoscowJS 27
"Доклад не про React", Антон Виноградов, MoscowJS 27
MoscowJS
"Web Audio Api", Анатолий Найда, MoscowJS 27
"Web Audio Api", Анатолий Найда, MoscowJS 27
MoscowJS
Ad

"FRP — делаем жизнь проще", Трдат Мкртчян, MoscowJS 19

  • 1. Functional Reactive Programming : Делаем жизнь проще Parcsis MoscowJS Meetup 19 Trdat Mkrtchyan
  • 2. 2 Часть I : ( Функциональная )
  • 3. 3 3
  • 4. 4 ( Плюсы ( ( Иммутабельные данные ) ( Отсутствие состояния ) ( Лень, как стратегия вычислений ) ( Частичное применение и карринг )) Получаем декларативный подход
  • 5. 5 ( Минусы ( ( Производительность ) ( Комьюнити слишком маленькое ) ( Состояние есть, но оно скрыто ))
  • 6. 6 Часть II : ( Реактивная )
  • 10. 10
  • 12. 12 arr = [1, 2, 3, 4] .map(square) .filter(moreThan3LessThan10) .reduce(add)
  • 13. 13 FRP >= FP Источник данных – это поток событий
  • 15. 15 Часть III : ( Программирование )
  • 16. 16 ( RxJS ( Microsoft Reactive Extensions ) github.com/Reactive-Extensions/RxJS ) ● Большое комьюнити ● Подробная документация
  • 17. 17 ( Bacon ( Juha Paananen @raimohanska ) github.com/baconjs/baconjs ) ● Простое API ● Ясная документация
  • 18. 18 ( Kefir ( Roman Pominov @rpominov ) github.com/pozadi/kefir ) ● Высокая производительность ● Активно развивается
  • 19. 19 ( Warden.js ( Trdat Mkrtchyan @zeffirsky ) github.com/zefirka/Warden.js ) ( ProAct ( Nickolay Tzvetinov @ntzvetinov ) github.com/proactjs/proactjs )
  • 20. 20 var timer; input.addEventListener('keydown', function(event){ if(event.keyCode == 13){ clearTimeout(timer); timer = setTimeout(function(){ doSomething(); }, 500); } }); Debounce в императивном варианте
  • 21. 21 Bacon.fromEventTarget(input, 'keydown') .filter(function(event){ return event.keyCode == 13 }) .debounce(500) .onValue(doSomething); Debounce в FRP
  • 22. 22 События var clicks = Bacon.fromBinder(function(sink) { document.addEventListener('click', sink); }); Ответы сервера var responses = Bacon.fromBinder(function(sink) { $.get('path/to', sink); }); Таймер var ticks = Bacon.fromBinder(function(sink) { setInterval(sink, 1000); }); Все что угодно – это stream 22
  • 23. 23 События var clicks = Bacon.fromBinder(function(sink) { document.addEventListener('click', sink); }); Ответы сервера var responses = Bacon.fromBinder(function(sink) { $.get('path/to', sink); }); Таймер var ticks = Bacon.fromBinder(function(sink) { setInterval(sink, 1000); }); Все что угодно – это stream 23
  • 24. 24 События var clicks = Bacon.fromBinder(function(sink) { document.addEventListener('click', sink); }); Ответы сервера var responses = Bacon.fromBinder(function(sink) { $.get('path/to', sink); }); Таймер var ticks = Bacon.fromBinder(function(sink) { setInterval(sink, 1000); }); Все что угодно – это stream 24
  • 25. 25 // пусть получаем данные из сокета в форме // {player : [Object] , score : [Integer] } var totalScore = 0; function calculateScore(data){ if(data.player.status == 'A'){ totalScore += data.score } } socket.on('score', calculateScore); Вычисления в императивном стиле
  • 26. 26 var totalScore = socket.stream('score') .filter(function (data){ return data.player.status == 'A'; }) .map('.score') .reduce(function (sum, score){ return sum + score; }) FRP упрощает вычисления + Вычисления не производятся, если они не нужны + Состояние чистое + Можно переиспользовать функции-обработчики
  • 29. 29 Controller app.controller('someCtrl', function ($scope, frp){ $scope.users = []; $scope.query = ''; frp.toStream($scope, 'query') .debounce(500) .map('.newResult') // привет $watch .filter(notEmpty) .onValue(function(query){ frp.http.get('search:users', { query: query }) .assign($scope, 'users'); }); } + В духе Angular - Вынуждены оборачивать службы Angular в FRP
  • 30. 30 Controller app.controller('someCtrl', function ($scope, frp){ $scope.users = []; $scope.query = ''; frp.toStream($scope, 'query') .debounce(500) .map('.newResult') // привет $watch .filter(notEmpty) .onValue(function(query){ frp.http.get('search:users', { query: query }) .assign($scope, 'users'); }); } + Никаких ng-change в разметке - Неявные $watch и $apply
  • 31. 31
  • 32. 32 ( Чуть больше магии, но видно, как это работает ) ( Все побочные действия – это setState ) ( Отлично встраивается во FLUX ) ( React ) 32
  • 33. 33 ( React ) componentDidMount: function(){ this.streamFrom(document, 'mousemove') .map(function(event){ return { x: event.clientX, y: event.clientY } }) .onValue(this.setState.bind(this)); }, render: function() { return <h1> X: {this.state.x}, Y: {this.state.y}</h1> }
  • 35. 35 Trdat Mkrtchyan Twitter: @zeffirsky Github: zefirka MoscowJS Meetup 19 (26. 02. 2015)