Skip to main content

Functional Reactive Programming

Most of this is my notes from Jafar Husain's FRP course (he is an awesome teacher).

"Functional Reactive Programming" sounded like some more buzz words to me when I first heard it from the awesome Timothy Quach. I was wrong.

Functional Reactive is a different programming paradigm. Things like Facebook's React have used the words "Imperative" and "Declarative". Essentially what "imperative" means is programming a solution using loops and if statements, describing how the problem is to be solved, in a step-by-step manner. What declarative means is just that, what needs to be solved. "I hereby declare ...". This is exactly what FRP facilitates, and it uses Observables.

Why?

Tracking state in async programs quickly becomes a nightmare. Just recently, updating someones React code was a nightmare because of listeners dotted around. FRP is easier to scale.

What is an Observable?

Observable === Collection + Time

or

a sequence of values that a data producer pushes to the consumer. It can also signal that it has completed.

That latter one is a complicated way of saying it is an array with a special api. For example, you can't repeat an asynchronous function with a loop; you can when it is an observable. So just a recap on higher order functions:

forEach applies the callback function to each of the items in a collection:

[1,2,3].forEach(x => console.log(x));

Map applies the callback to every item in the collection, creating a new value, then creates a new array with the results of applying that function to each value in the array:

[1,2,3].map(x => x + 1);

Filter is a test function, it applies a test to every single value and if it passes the test it gets added to the new array that is returned:

[1,2,3].filter(x => x + 1);

So using an observable:

var mouseMoves = Observable.fromEvent(element, 'mousemove');
var subscription = mouseMoves
  .forEach(
    event => console.log(event),
    error => console.log(error),
    () => console.log('done')
  );

subscription.dispose();

With DOM event handlers, old school would be like this:

var button = document.getElementById('myButton');
button.addEventListener('click', function () {
  ...
});

Observable would be like:

var button = document.getElementById('myButton');
button.addEventListener('click', function (event) {},
  function (error) {},
  function () { console.log('done'); }
});

OR, you can pass an object:

{
	onNext: function (event) {},
	onError: function (error) {},
	onDone: function () {}
}

To create an observable object all you need to do is provide a standard observable api. Four things are important:

  1. What streams do we have, or functions that give me streams
  2. What do I want to create
  3. Map, filter, retry into the stream we want
  4. Consume data and put it on screen

Observable.fromEvent is a function that turns an event into an observable.

The difference between forEach on an Array and an Observable is that with an Array, the loop waits until the next value arrives. With an Observable, a value is pushed to the client whenever it arrives.

function Observable (forEach) {
  this._forEach = forEach;
}

Observable.prototype = {
  forEach: function (onNext, onError, onCompleted) {
    if (typeof onNext !== 'function') {
      return this._forEach({
        onNext: onNext,
        onError: onError || function () {  },
        onCompleted: onCompleted || function () {  }
      });
    } else {
      return this._forEach(onNext);
    }
  }
};

Observable.fromEvent = function (dom, eventName) {
  return new Observable(function forEach (observer) {
    var handler = function (event) {
      observer.onNext(event);
      dom.addEventListener(eventName, handler);
      return {
        dispose: function () {
          dom.removeEventListener(eventName, handler);
        }
      }
    }
  });
};

var obs = new Observable(function (observer) {});

Core Functions

forEach, map, and filter all look at one value at a time so is ideal for changing each item or running a test condition against it. Reduce looks at two pieces of information and compares values so it is ideal for mathematical operations or things like finding the greatest length.

Resources