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

Let's take a look at flatMapLatest()!

 

jsfiddle

Real world usage

  • RxJS on the client
  • RxJava on the server
  • Netflix engineering

Questions?

Resources

RxJS

By Calvin Belden

RxJS

  • 1,132