Reactive Programming with RxJS
![](https://s3.amazonaws.com/media-p.slid.es/uploads/471017/images/2369643/Rx_Logo_S.png)
Aliaksei Bahachuk
Reactivity is modern, but What is it?
![](https://s3.amazonaws.com/media-p.slid.es/uploads/471017/images/2428769/044.gif)
Reactive Programming
Programming paradigm oriented around data flows and the propagation of change (wiki)
Observables + LINQ + Schedulers (Microsoft)
Programming paradigm with asynchronous data streams (Andre Staltz)
Reactive Programming
a := 1;
b := 2;
c := a + b; //c === 3
Reactive Programming
c := a + b; //c === 3
a := 3 // c === ???
Reactive Programming
a := 1;
b := 2;
c := a + b; //c === 3
a := 3; //c === 5
![](https://s3.amazonaws.com/media-p.slid.es/uploads/471017/images/2378439/1.png)
Cell
-
type Cell(a) = t -> a
-
Behaviour/signal/cell
![](https://s3.amazonaws.com/media-p.slid.es/uploads/471017/images/2433917/property.png)
Data Flow
-
type Stream(a) = [(t, a)]
![](https://s3.amazonaws.com/media-p.slid.es/uploads/471017/images/2433970/stream.png)
Everything can be a stream
-
Events
-
Variables
-
Data Structures
-
You can actually model every input/output that happens in a browser as a stream (or a stream of streams)
Everything can be a stream
![](https://s3.amazonaws.com/media-p.slid.es/uploads/471017/images/2434067/mind.gif)
Can we, effectively, build a program using this notion?
Meet your new friend:
The Observable
Your friendly neighbor: RxJS
Reactive Extensions
Are a set of libraries for composing asynchronous and event-based programs using observable sequences and fluent query operators
Rx is everywhere
![](https://s3.amazonaws.com/media-p.slid.es/uploads/471017/images/2369643/Rx_Logo_S.png)
Java
JavaScript
.Net
Ruby
Swift
C++
Clojure
Scala
What is the most asynchronous?
User
![](https://s3.amazonaws.com/media-p.slid.es/uploads/471017/images/2394750/0_large.jpg)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/471017/images/2394752/keyboard-symbols-pictures.jpg)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/471017/images/2394753/magic_645.jpg)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/471017/images/2394754/download.jpg)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/471017/images/2394757/36607.jpg)
More async data streams
-
XHR requests
-
WebSocket
-
Promises
-
Events
-
Dom Inputs
-
Web Worker
-
Web RTC
RxJS operators
RxJS operators
RxJS operators: map
![](https://s3.amazonaws.com/media-p.slid.es/uploads/471017/images/2395838/Screen_Shot_2015-09-18_at_3.01.31_PM.png)
resStream
RxJS operators: delay
![](https://s3.amazonaws.com/media-p.slid.es/uploads/471017/images/2395845/Screen_Shot_2015-09-18_at_3.04.55_PM.png)
resStream
RxJS operators: debounce
![](https://s3.amazonaws.com/media-p.slid.es/uploads/471017/images/2395847/Screen_Shot_2015-09-18_at_5.09.49_PM.png)
resStream
RxJS operators: merge
![](https://s3.amazonaws.com/media-p.slid.es/uploads/471017/images/2634649/Screen_Shot_2015-09-18_at_5.09.49_PM.png)
resStream
RxJS operators: combineLatest
![](https://s3.amazonaws.com/media-p.slid.es/uploads/471017/images/2634702/Screen_Shot_2015-09-18_at_5.09.49_PM1.png)
resStream
RxJS operators: zip
![](https://s3.amazonaws.com/media-p.slid.es/uploads/471017/images/2634714/Screen_Shot_2015-09-18_at_5.09.49_PM12.png)
resStream
Let's create a morse-code decoder!
Morse-code decoder
![](https://s3.amazonaws.com/media-p.slid.es/uploads/471017/images/2394787/0_large.jpg)
click...
click...
click.............
click...
Morse-code decoder
click...
click...
click.............
click...
Morse-code decoder
-
Dom events (keydown, keyup)
-
Start signal/End signal
-
Dot/Dash/Whitespace
-
Letter
-
Word/Sentence
Morse-code decoder
![](https://s3.amazonaws.com/media-p.slid.es/uploads/471017/images/2395509/734f51149b4f0b1ec570fbddddbd78cc.jpg)
Morse-code decoder
-
"." = ~400ms
-
"_" = 3 * "."
-
between codes = "."
-
between letters = 3 * "."
-
between words = 7 * "."
![](https://s3.amazonaws.com/media-p.slid.es/uploads/471017/images/2637560/29626547728bd20f526fd09db50ab294.jpg)
Morse-code decoder
const keyUps = Rx.Observable
.fromEvent(document, 'keyup');
const keyDowns = Rx.Observable
.fromEvent(document, 'keydown');
Morse-code decoder
const spaceKeyUps = keyUps.filter((data) => data.keyCode === 32);
const spaceKeyDowns = keyDowns.filter((data) => data.keyCode === 32);
![](https://s3.amazonaws.com/media-p.slid.es/uploads/471017/images/2634743/Screen_Shot_2015-09-18_at_5.09.49_PM3.png)
Morse-code decoder
const signalStartsRaw = spaceKeyDowns.map(() => "start");
const signalEndsRaw = spaceKeyUps.map(() => "end");
const signalStartsEnds = Rx.Observable
.merge(signalStartsRaw, signalEndsRaw)
.distinctUntilChanged();
![](https://s3.amazonaws.com/media-p.slid.es/uploads/471017/images/2634760/Screen_Shot_2015-09-18_at_5.09.49_PM34.png)
Morse-code decoder
const signalStarts = signalStartsEnds
.filter((ev) => ev === "start")
.timestamp();
const signalEnds = signalStartsEnds
.filter((ev) => ev === "end")
.timestamp();
const spanStream = signalStarts.flatMap((start) => {
return signalEnds.map((end) => end.timestamp - start.timestamp)
.first();
});
Morse-code decoder
![](https://s3.amazonaws.com/media-p.slid.es/uploads/471017/images/2395543/c52ae5f2b51e4fb49a99ea27d40dd402.png)
Morse-code decoder
const SPAN = 400;
const dotsStream = spanStream
.filter((v) => v <= SPAN)
.map(() => ".");
const lineStream = spanStream
.filter((v) => v > SPAN)
.map(() => "-");
Morse-code decoder
const dotsAndLines = Rx.Observable.merge(dotsStream, lineStream);
// [['.', '.', '-'], ['-', '.', '-'] ... ]
const letterCodes = dotsAndLines.buffer(letterWhitespaces);
// ['A', 'B' ...]
const lettersStream = letterCodes
.map((codes) => morse.decode(codes.join("")));
Morse-code decoder
![](https://s3.amazonaws.com/media-p.slid.es/uploads/471017/images/2395597/morse.png)
demo — http://alexmost.github.io/morse/
source — https://github.com/AlexMost/morse
Morse-code decoder
![](https://s3.amazonaws.com/media-p.slid.es/uploads/471017/images/2408695/pasted-from-clipboard.png)
What else?
Component bindings
![](https://s3.amazonaws.com/media-p.slid.es/uploads/471017/images/2637651/clouds-png-cloud.png)
Component bindings
click...
click...
click.............
click...
click
category.
comp.
bundle.
package.
Component bindings
![](https://s3.amazonaws.com/media-p.slid.es/uploads/471017/images/2637651/clouds-png-cloud.png)
Component bindings
![](https://s3.amazonaws.com/media-p.slid.es/uploads/471017/images/2637684/board.jpg)
Problems RxJS solves
-
Data Manipulation
-
Events handling
-
Callback Hell
-
Promise Hell
-
Comet/Async Manipulation
-
Race Conditions
-
Complex State
-
Tests
![](https://s3.amazonaws.com/media-p.slid.es/uploads/280009/images/2157336/cat1.png)
RxJS problems
Complexity
![](https://s3.amazonaws.com/media-p.slid.es/uploads/471017/images/2378713/5fa6b81fbe1146508c79f1b2e486aef2.jpg)
Integration with imperative part of code
![](https://s3.amazonaws.com/media-p.slid.es/uploads/471017/images/2378733/Incompatible-software-10.6-news350.jpg)
Documentation
Projects each element of an observable sequence to an observable sequence and merges the resulting observable sequences or Promises or array/iterable into one observable sequence.
Cascade Updating
Cascade Updating
Cascade Updating/Exceptions
RxJS with other frameworks
RxJS with Angular - rx.angular.js
angular.module('example', ['rx'])
.controller('AppCtrl', function($scope, $http, rx) {
function searchWikipedia (term) {
return rx.Observable
.fromPromise($http({}))
.map(function(response){ return response.data[1]; });
}
$scope.search = '';
$scope.results = [];
$scope.$createObservableFunction('click')
.map(function () { return $scope.search; })
.flatMapLatest(searchWikipedia)
.subscribe(function(results) {
$scope.results = results;
});
});
RxJS with Angular2 - inside
![](https://s3.amazonaws.com/media-p.slid.es/uploads/471017/images/2378601/ng2-logo.png)
RxJS with React - rx-react
![](https://s3.amazonaws.com/media-p.slid.es/uploads/471017/images/2395961/e7ec8873df034ed8ad308b1142719632.png)
RxJS with others
![](https://s3.amazonaws.com/media-p.slid.es/uploads/471017/images/2637763/mootools.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/471017/images/2637761/extjs.jpg)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/471017/images/2637759/backbone.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/471017/images/2637756/86896.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/471017/images/2637752/0cf15665a9146ba852bf042b0652780a.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/471017/images/2637758/1436439824nodejs-logo.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/471017/images/2637778/_______________.png)
Alternative?
Bacon
![](https://s3.amazonaws.com/media-p.slid.es/uploads/471017/images/2395991/729900.jpg)
Kefir
![](https://s3.amazonaws.com/media-p.slid.es/uploads/471017/images/2395999/gastrit-kefir2.jpg)
Highland
I want more hardcore!
Javelin and ClosureScript
(defc test-results
{:scores [74 51 97 88 89 91 72 77 69 72 45 63]
:proctor "Mr. Smith"
:subject "Organic Chemistry"
:sequence "CHM2049"})
(defc= test-results-with-mean
(let [scores (:scores test-results)
mean (/ (reduce + scores) (count scores))
grade (cond (<= 90 mean) :A
(<= 80 mean) :B
(<= 70 mean) :C
(<= 60 mean) :D
:else :F)]
(assoc test-results :mean mean :grade grade)))
Cycle.js
-
RxJS
-
Side effects/Logic
-
Composition
-
Streams, streams, streams, streams
![](https://s3.amazonaws.com/media-p.slid.es/uploads/471017/images/2610993/12686838.png)
Questions?
Reactive Programming with RxJS
By Aliaksei Bahachuk
Reactive Programming with RxJS
An overview of RxJS
- 1,156