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

35
Functional Reactive Programming : Делаем жизнь проще Parcsis MoscowJS Meetup 19 Trdat Mkrtchyan

Upload: moscowjs

Post on 14-Jul-2015

362 views

Category:

Software


4 download

TRANSCRIPT

Functional Reactive Programming:

Делаем жизнь проще

Parcsis

MoscowJS Meetup 19

TrdatMkrtchyan

2

Часть I :

( Функциональная )

33

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

Controllerapp.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

Controllerapp.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)