Functional

Reactive

JS

What is Reactive Programming?

...

Programming paradigm oriented around data flows and the propagation of change

What is Reactivity?

in literal sense

Something happening in "reaction" to some action

in the context of programming

...

When something changes over time, everything dependent on the change shall react

Forgotten Dimension of async code

Time

A simple example

var firstName = new ReactiveVar('anon');  //a well, reactive variable
var lastName = new ReactiveVar('anon');

var fullName = new ReactiveVar();

Tracker.autorun(function(){
  //the reaction (aka Reactive Computation)
  fullName.set(firstName.get() + ' ' + lastName.get());
});
> firstName.set('First');
> console.log(fullName.get());
> First anon

> lastName.set('Last');
> console.log(fullName.get());
> First Last

another example Promise

A time dependent (temporal) construct which informs us when it gets its value some time in future

Reactive Programming

Programming Oriented around

  • data flows : data asynchronously flowing through the app over time
  • propagation of change : change in the data cause any dependencies to react

Functional Reactive Programming

...

A programming paradigm for reactive programming using the building blocks of functional programming

very basic building blocks of FP

  • map <iterable> -> (value) -> <iterable>
  • reduce <iterable> -> (acc, value) -> <iterable>
  • filter <iterable> -> (value) -> <iterable>
  • ...

FP is Beautiful

eg Composibility

  /* generate a function which takes a json file's content
     and remove all JS comments from it
  */
  var sanitizeJson = R.pipe(R.split('\n'),
                            R.map(R.trim),
                            R.filter(R.strIndexOf('//')),
                            R.join('\n'));
                          |   Imperative | Temporal   |
                          |--------------+------------|
                          |   Value      | Promise    |
                          |              |            |
                          |   Iterable   | Observable |

Iterable / Array

  • A snapshot of data


Observable

  • Data set that updates and reacts as system changes over time

Observable is an asynchronous stream of data which emits

  • new data
  • error
  • completed signal

    --a---b-c---d---X---|->

    ...

    We listen to the stream by subscribing to emitted events

Observer pattern on

steroids

Any value which changes over time can be converted to an Observable

  • Variable
  • User Input
  • Ajax calls
  • Events

RXjs

  • Reactive extensions for JavaScript
  • Developed and maintained by Microsoft
  • Has alternatives in many languages
  • Java, C++, C# and many more
Iterable Observable
getDataFromLocalMemory()
  .filter (s => s != null)
  .map(s => s + 'transformed')
  .forEach(s => console.log('next => %s', it))
getDataFromNetwork()
  .filter (s => s != null)
  .map(s => s + 'transformed')
  .subscribe(s => console.log('next => %s', it))

example

  var countButtonClicks = Rx.Observable.fromEvent(countButton, 'click'),
  stopButtonClicks = Rx.Observable.fromEvent(stopButton, 'click');

  countButtonClicks
    .takeUntil(stopButtonClicks)  //keep taking input from clicks on countButton
    .forEach(function(e) {       // until stopButtonClicks recieves a value
       state.count += 1;
       countNode.innerHTML = state.count;
    });

0

little bigger example

  var input = document.getElementById('input');
  var dictionarySuggest = Rx.Observable.fromEvent(input, 'keyup')
    .map(function () { return input.value; })
    .filter(function (text) { return !!text; })
    .distinctUntilChanged()
    .throttle(250)
    .flatMapLatest(searchWikipedia)
    .subscribe(
      function (results) {
        list = [];
        list.concat(results.map(createItem));
      },
      function (err) {
        logError(err);
      }
    );

another example

var sprite = document.getElementById("sprite"),
    container = document.getElementById("sprite-container");

var spriteMouseDowns = Rx.Observable.fromEvent(sprite, "mousedown"),
    spriteContainerMouseMoves = Rx.Observable.fromEvent(container, "mousemove"),
    spriteContainerMouseUps = Rx.Observable.fromEvent(container, "mouseup");

var spriteMouseDrags =
    // For every mouse down event on the sprite...
    spriteMouseDowns.
      concatMap(function(contactPoint) {
        // ...retrieve all the mouse move events on the sprite container...
        return spriteContainerMouseMoves.
          // ...until a mouse up event occurs.
          takeUntil(spriteContainerMouseUps).
          map(function(movePoint) {
            return {
              pageX: movePoint.pageX - contactPoint.offsetX,
              pageY: movePoint.pageY - contactPoint.offsetY
            };
          });
    });

// For each mouse drag event, move the sprite to the absolute page position.
spriteMouseDrags.forEach(function(dragPoint) {
  sprite.style.left = dragPoint.pageX + "px";
  sprite.style.top = dragPoint.pageY + "px";
});

Demo

Resources