Reactive Programming with RxJS
Aliaksei Bahachuk
Reactivity is modern, but What is it?
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
Cell
-
type Cell(a) = t -> a
-
Behaviour/signal/cell
Data Flow
-
type Stream(a) = [(t, a)]
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
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
Java
JavaScript
.Net
Ruby
Swift
C++
Clojure
Scala
What is the most asynchronous?
User
More async data streams
-
XHR requests
-
WebSocket
-
Promises
-
Events
-
Dom Inputs
-
Web Worker
-
Web RTC
RxJS operators
RxJS operators
RxJS operators: map
resStream
RxJS operators: delay
resStream
RxJS operators: debounce
resStream
RxJS operators: merge
resStream
RxJS operators: combineLatest
resStream
RxJS operators: zip
resStream
Let's create a morse-code decoder!
Morse-code decoder
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
Morse-code decoder
-
"." = ~400ms
-
"_" = 3 * "."
-
between codes = "."
-
between letters = 3 * "."
-
between words = 7 * "."
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);
Morse-code decoder
const signalStartsRaw = spaceKeyDowns.map(() => "start");
const signalEndsRaw = spaceKeyUps.map(() => "end");
const signalStartsEnds = Rx.Observable
.merge(signalStartsRaw, signalEndsRaw)
.distinctUntilChanged();
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
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
demo — http://alexmost.github.io/morse/
source — https://github.com/AlexMost/morse
Morse-code decoder
What else?
Component bindings
Component bindings
click...
click...
click.............
click...
click
category.
comp.
bundle.
package.
Component bindings
Component bindings
Problems RxJS solves
-
Data Manipulation
-
Events handling
-
Callback Hell
-
Promise Hell
-
Comet/Async Manipulation
-
Race Conditions
-
Complex State
-
Tests
RxJS problems
Complexity
Integration with imperative part of code
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
RxJS with React - rx-react
RxJS with others
Alternative?
Bacon
Kefir
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
Questions?
Reactive Programming with RxJS
By Aliaksei Bahachuk
Reactive Programming with RxJS
An overview of RxJS
- 1,186