2. About me
Mostovenko Alexander
Python developer at
Writing mostly in python and coffeescript.
Love FP stuff.
Traveling, snowboarding, cycling.
https://twitter.com/MostovenkoA
https://github.com/AlexMost
3. Why Rx.js and not another FRP lib?
● Implemented in a lot of languages
(.NET, Java, Ruby, Python, Clojure, Scala,
Haskell, Objective-C).
● Has a huge amount of docs and examples.
● Why not?
29. Callback vs Black hole
some_async_func(function(err, result) {
// ... looks like we are in trap
another_wonderful_func(function(err, result){
// ... you are in trap
});
});
35. Why we should look at Observable?
1. Promise represents only single value.
2. How to cancel?
3. Lazy execution.
4. We can work with Observable as easy as with
promise.
38. Observable
var source = Rx.Observable.create((observer) =>
// some async operation
observer.onNext(data)
// or ..
observer.onError(data)
// or ..
observer.onCompleted(data)
);
source.subscribe(
(data) => {}
(err) => {}
)
39. Observlable vs promise example
var source = Rx.Observable.create((observer) => {
setTimeout(() => {
console.log("observable timeout hit");
observer.onNext(25);
}, 500);
console.log('observable started')});
source.subscribe(x => console.log(`observable value ${x}`));
Observable
> observable started
> observable timeout hit
> observable value 25
40. Observlable vs promise example
var promise = new Promise((resolve) => {
setTimeout(() => {
console.log("promise timeout hit");
resolve(25);
}, 500);
console.log("promise started");});
promise.then(x => console.log(`promise value ${x}`));
Promise
> promise started
> promise timeout hit
> promise value 25
44. Asynchronous programming landscape
multiple
values
single
value
sync async
a = f(x) a = f(x).then(...)
collection = [1, 2, 3]
a = collection
.filter((v) => v > 2)
move = Rx.Observable.fromEvent(document, 'mousemove')
my_moves = move
.filter((ev) => ev.clientX > 100)
my_moves.subscribe(...)
Promise
Array
value
Observable
45. How to create Observable
● Observable.create
● Observable.fromEvent
● Observable.fromNodeCallback
● Observable.fromArray
● Observable.fromPromise
46. Drag & Drop example
What if i told you ….
That mouse move event is an array and you
can map, filter over it?
47. var dragTarget = document.getElementById('dragTarget');
// Get the three major events collections
var mouseup = Rx.DOM.fromEvent(dragTarget, 'mouseup');
var mousemove = Rx.DOM.fromEvent(document, 'mousemove');
var mousedown = Rx.DOM.fromEvent(dragTarget, 'mousedown');
var mousedrag = mousedown.flatMap(({offsetX, offsetY}) => {
return mousemove
.map(({clientX: x, clientY: y}) => {
return {left: x - offsetX, top: y - offsetY}})
.takeUntil(mouseup)
});
var subscription = mousedrag.subscribe((pos) => {
dragTarget.style.top = pos.top + 'px';
dragTarget.style.left = pos.left + 'px';
});
48. var dragTarget = document.getElementById('dragTarget');
// Get the three major events collections
var mouseup = Rx.DOM.fromEvent(dragTarget, 'mouseup');
var mousemove = Rx.DOM.fromEvent(document, 'mousemove');
var mousedown = Rx.DOM.fromEvent(dragTarget, 'mousedown');
var mousedrag = mousedown.flatMap(({offsetX, offsetY}) => {
return mousemove
.map(({clientX: x, clientY: y}) => {
return {left: x - offsetX, top: y - offsetY}})
.takeUntil(mouseup)
});
var subscription = mousedrag.subscribe((pos) => {
dragTarget.style.top = pos.top + 'px';
dragTarget.style.left = pos.left + 'px';
});
Create observable collections
from DOM events
49. var dragTarget = document.getElementById('dragTarget');
// Get the three major events collections
var mouseup = Rx.DOM.fromEvent(dragTarget, 'mouseup');
var mousemove = Rx.DOM.fromEvent(document, 'mousemove');
var mousedown = Rx.DOM.fromEvent(dragTarget, 'mousedown');
var mousedrag = mousedown.flatMap(({offsetX, offsetY}) => {
return mousemove
.map(({clientX: x, clientY: y}) => {
return {left: x - offsetX, top: y - offsetY}})
.takeUntil(mouseup)
});
var subscription = mousedrag.subscribe((pos) => {
dragTarget.style.top = pos.top + 'px';
dragTarget.style.left = pos.left + 'px';
});
Using power of Rx, combine
existing event streams to produce
mouse drag event collection
50. var dragTarget = document.getElementById('dragTarget');
// Get the three major events collections
var mouseup = Rx.DOM.fromEvent(dragTarget, 'mouseup');
var mousemove = Rx.DOM.fromEvent(document, 'mousemove');
var mousedown = Rx.DOM.fromEvent(dragTarget, 'mousedown');
var mousedrag = mousedown.flatMap(({offsetX, offsetY}) => {
return mousemove
.map(({clientX: x, clientY: y}) => {
return {left: x - offsetX, top: y - offsetY}})
.takeUntil(mouseup)
});
var subscription = mousedrag.subscribe((pos) => {
dragTarget.style.top = pos.top + 'px';
dragTarget.style.left = pos.left + 'px';
});
Subscribe on mouse drag events,
updating top and left attributes
51. Observable are first class events
Can be:
- passed as a parameter
- returned from a function
- assigned to a variable
52.
53. Some common basic operations
map
filter
reduce
zip
merge
flatMap
...
https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/observable.md
80. dispatchActions = (view, eventStream, store) ->
incrementClickStream = eventStream
.filter(({action}) -> action is "increment_click_count")
.do(-> store.incrementClicksCount())
Rx.Observable.merge(
incrementClickStream
# some more actions here for updating view ...
).subscribe(
-> view.setProps getViewState(store)
(err) ->
console.error? err)
RxReact (simple click count)
81. dispatchActions = (view, eventStream, store) ->
incrementClickStream = eventStream
.filter(({action}) -> action is "increment_click_count")
.do(-> store.incrementClicksCount())
Rx.Observable.merge(
incrementClickStream
# some more actions here for updating view ...
).subscribe(
-> view.setProps getViewState(store)
(err) ->
console.error? err)
RxReact (simple click count)
stream from view for increment and storage
modification
82. dispatchActions = (view, eventStream, store) ->
incrementClickStream = eventStream
.filter(({action}) -> action is "increment_click_count")
.do(-> store.incrementClicksCount())
Rx.Observable.merge(
incrementClickStream
# some more actions here for updating view ...
).subscribe(
-> view.setProps getViewState(store)
(err) ->
console.error? err)
RxReact (simple click count)
merge all streams that can modify UI
83. dispatchActions = (view, eventStream, store) ->
incrementClickStream = eventStream
.filter(({action}) -> action is "increment_click_count")
.do(-> store.incrementClicksCount())
Rx.Observable.merge(
incrementClickStream
# some more actions here for updating view ...
).subscribe(
-> view.setProps getViewState(store)
(err) ->
console.error? err)
RxReact (simple click count)
update UI, making setProps on view
component
84. RxReact (simple click count)
More complex case
1. Decrement.
2. Sync with server (per 1 second).
3. Sync only if value changed.
4. Show sync success message.
5. Hide success message after 2 seconds.
demo - http://alexmost.github.io/RxReact/hello_world2/public/index.html
code - https://github.com/AlexMost/RxReact/tree/master/hello_world2/hello_world2
90. Conclusion
● Rx is a powerful tool for writing async code
● Helps to write modular and composable code
● Solves a lot of hard testing problems
● Solves problem of error handling and resource
management