Rx
Reactive Extensions
Composing asynchronous streams of data
What is Rx?
Reactive Extensions is a library to compose asynchronous and event-based programs using observable collections and LINQ-style query operators.
Supported Runtimes
- JavaScript
- C#
- Java
- Python
- C++
- Ruby
- ...and others
So What?
- Rx allows you to treat asynchronous events as a stream of data
- Encourages a declarative, readable programming style
- Tons of useful LINQ-like operators
- Streams and Promises go together like tots and ketchup
Let's take a peak...
Observable (ie a Stream)
- An Observable represents a time-ordered stream of data
- Observables can emit three types of things:
- value
- error
- "completed" signal
- Rx provides a rich, fluent API for operating on these streams
- map(), filter(), selectMany(), delay(), SO MANY MORE
Key Idea
There's this really important idea of a stream as a push-based collection. Here, the source of data is in charge of pushing new values into the data stream.
This is in contrast to a pull-based collection (ie arrays, lists, etc.) where the consumer is in charge of pulling or getting successive values.
This allows us to model asynchronous events in a very natural way.
MARBLE DIAGRAMS ARE FUN!!!
Streams - Illustrated
Let's Create an Observable of Double Clicks
var element = document.getElementById('my-element');
var doubleclicks = Rx.Observable.fromEvent(element, 'mousedown')
.timeInterval()
.filter(function (x) { return x.interval < 300});
doubleclicks.subscribe(function () {
alert('Double clicked!');
});
var doubleclicks = Rx.Observable.fromEvent(element, 'mousedown')
.timeInterval()
.filter(function (x) { return x.interval < 300});
timeInterval()
filter()
More Examples
Dealing with several Promises
var http = require('http');
var parse = require('parse');
var urls = [
'http://www.biz.com',
// ...lots more
];
// Create an Observable of results
var results = Rx.Observable.from(urls)
.selectMany(function (url) { return http.get(url) }) // selectMany is great!!
.map(function (response) { return parse(response.body) });
results.subscribe(function (data) {
// Prints the results in the order that the http.get promises resolve
console.log(data);
});
Drag and Drop
Rx.Observable.mousedrag = function (element) {
var mousedown = Rx.Observable.fromEvent(element, 'mousedown');
var mousemove = Rx.Observable.fromEvent(document, 'mousemove');
var mouseup = Rx.Observable.fromEvent(document, 'mouseup');
return mousedown.
selectMany(function (md) {
return mousemove.
select(function (move) {
return {
x: parseInt(element.css('left')) + move.movementX,
y: parseInt(element.css('top')) + move.movementY
};
}).
takeUntil(mouseup);
});
};
var $button = $('#click-me');
var buttonDrags = Rx.Observable.mousedrag($button)
buttonDrags.subscribe(function (drag) {
$button.css('left', drag.x);
$button.css('top', drag.y);
});
Pagination
more fun with promises
Real world usage
Questions?
Resources
RxJS
By Calvin Belden
RxJS
- 1,145