Transform your web applications with reactive functional programming

This is not…​

https://openclipart.org/detail/22519/crowd
Notes
  • This is not a talk on React - the web framework put out by facebook

Reactive programming with Rx.js

Notes
  • Rather this session addresses functional reactive programming in javascript
  • by the end of the session we should have a good understanding of what both functional and reactive have in this context

The plan

  • Async JavaScript review
  • Observables are what?
  • Use cases and examples
http://www.flickr.com/photos/jdhancock/5845280258/
Notes
  • In this session we will run through a quick review of Asynchronous programming with javascript
  • We will introduce the concept of the Observable, and look at how it enables us to handle async in a functional reactive way
  • We’ll look at a bunch of examples to demonstrate the power of Observables

Who am I?

http://leslycorazon.wikispaces.com/file/detail/head-silhouette-with-question-mark.png/319199232
  • Brian Leathem
  • Software Engineer @ Red Hat
  • Works on developer tools and frameworks
Notes

*

Who are you?

https://openclipart.org/detail/22519/crowd
Notes
  • And how about you guys, lets' get an idea of the audience we have here today.
  • Can I see a show of hands
    • from those in the audience who consider themselves proficient with javascript?
    • who are familiar with functional programming in other contexts?

Async JavaScript

Notes
  • Great, with the introductions out of the way let’s dive into the good stuff

Async Javascript

  • XHR
  • Animations
  • Timeout/Interval
  • Event Listeners
Notes
  • Javascript runs with a single event loop
  • Long running-code can block this loop
  • Asynchronous programming gives us a way to break out of this event loop
  • Some familiar uses cases include XHR, Animations, timers, and event listeners
  • Whole host of new Async APIs with the new ES6 APIs

Callbacks

Asynchronous javascript:

function asyncTask(args, callback) {
  // do stuff
  callback()
}
https://openclipart.org/detail/202235/protester
Notes
  • The standard means of working with asynchronous javascript
  • An synchronous API will take a callback function as a parameter, and invoke that function when it’s task is complete

Invoking asyncTask

asyncTask(args, function() {
  // task is done here!
})
Anonymous function:
  • simple
  • concise
  • well-accepted pattern
Notes
  • Invoking such an async API involves creating a function to pass in as a callback
  • This works great, but breaks down quickly when you have multiple async tasks to perform

Nesting async calls - serial

asyncTask1(args, function() {
  asyncTask2(args, function() {
    asyncTask1(args, function() {
      // task is done here!
    })
  })
})
callback
Notes
  • If you want to invoke those tasks serially, you have to nest them
  • each task is called via the callback of the previous task
  • quickly leads to what is known as callback hell
  • code is difficult to read, and difficult to debug

Simultaneous callbacks - parallel

var result1=false; result2=false; // state!!

asyncTask1(function(){a1=true; doAction()}
asyncTask2(function(){a2=true; doAction()}

function doAction() {
  if (a1 && a2) {
    …
  }
}
Notes
  • The story does not get any better when running async tasks in parallel
  • A common pattern is to share a callback between tasks
    • and track task completion via a shared state object
  • What about error handling?

Promises to the rescue!

Serial:
asyncTask1.then(asyncTask2).then(function() {
  // success
}, function(err) {
  // error
})

Parallel:
Promise.all(asyncTask1, asyncTask2).then(...)
Notes
  • The promise API was developed to help manage this complexity
  • It allows us to chain asynchronous tasks, rather then nest them
  • and offers library functions for executing them in parallel
  • Error handling is also well-defined and consistent

What about events?

http://www.slideshare.net/stefanmayer13/functional-reactive-programming-with-rxjs

From: http://www.slideshare.net/stefanmayer13/functional-reactive-programming-with-rxjs

Notes
  • The promise API works great for dealing with single events
    • like an XHR callback for instance
  • But what about multi-valued events, like mouse or keyboard events?
  • We need an altogether different construct to deal with such multi-valued events
  • This is where the Observable comes in

Observable what?!

Think of an observable as a collection-in-time

Same functional tools apply
  • forEach
  • filter
  • map
  • …​
Notes
  • But what is this Observable thing Brian?
  • I like to relate the observable to a an array, or collection.
  • but instead of being a collection in "space", it’s a collection in "time"
  • We will see how we can take the same functional tools we use to manipulate regular collections
    • and apply them to these collections-in-time

Imperative vs. Functional

Iterating over an array

Imperative:
for (var i=0; i < a.length; i++) {
  item = a[i];
  // item.doAction()
}
Functional:
a.forEach(function(item) {
  // item.doAction()

})
Notes
  • So exactly what is functional programming?
  • I find it useful to think about functional programming as inverting the question of "who is in control?"
  • In an imperative approach
    • the developer explicitly iterates over a collection
    • takes a reference to each object, and manipulates that object
  • In a functional approach
    • The developer simply states what should be done to each object, and lets the container/library iterate over each one
  • This can be seen in these two code samples where we want to iterate over a collection

A Collection

See the Pen Collection | Iden by Brian Leathem (@bleathem) on CodePen.

Notes
  • To build on this analogy of Observables as collections in time
  • I built a series of visualizations that demonstrate operations on objects in each of these collections
  • A collection then is like a bag of objects
  • We have all the objects at hand, and can easily grab a reference to each one if we want
  • Look at the code

An Observable

See the Pen Observable by Brian Leathem (@bleathem) on CodePen.

Notes
  • An observable then is a collection in time
  • or an Event collection
  • We can’t grab a reference to each object, because not all objects exist yet
  • This looks like an entirely different beast than the collection we just saw
  • So how is it we will be able to use the same tools to manipulate both these concepts?

Rx.js

Reactive Extensions for JavaScript

…​is a set of libraries to compose asynchronous and event-based programs using observable collections and Array#extras style composition in JavaScript

Notes
  • The reactive extensions project provides an Observable implementation and an API for manipulating Observables
  • We are next going to look closely at a subset of this API, and see how the functional approach applies to both collections and collections-in-time

Some basic transforms

  • map
  • reduce
  • mergeAll
  • reduce
  • zip
Notes
  • Focus on these base ingredients
  • We’ll see more as we get into later examples

map

.map(function(x) {
  return {
    id: x.id
  , color: 'green'
  , size: x.size
  , type: 'square'
  };
});

Map each shape

into a green square

of the same size

Collection map

See the Pen Operating on a Collection by Brian Leathem (@bleathem) on CodePen.

Observable map

See the Pen Map an Observable by Brian Leathem (@bleathem) on CodePen.

mergeAll

.map(function(x) {
    var y = _.clone(x);
    y.id = y.id + 80;
    y.color = 'green';

    var z = _.clone(x);
    y.size = y.size / 1.5;
    z.size = z.size / 1.5;

    return [y, z];
  })
  .mergeAll();

Nested Collections

See the Pen Map a nested Collection by Brian Leathem (@bleathem) on CodePen.

Nested Collections mergeAll

See the Pen MergeAll a Collection by Brian Leathem (@bleathem) on CodePen.

Observable mergeAll

See the Pen MergeAll an Observable by Brian Leathem (@bleathem) on CodePen.

flatMap

flatMap is a shorthand for a map followed by a mergeAll.

.flatMap(function(x) {
    var y = _.clone(x);
    y.id = y.id + 80;
    y.color = 'green';

    var z = _.clone(x);
    y.size = y.size / 1.5;
    z.size = z.size / 1.5;

    return [y, z];
  });

reduce

var outputData = inputData
  .reduce(function(acc, x) {
    return {
      id: x.id
    , color: 'green'
    , size: acc.size + x.size
    , type: 'square'
    };
  }, {size: 0});

Collection reduce

See the Pen Reduce a Collection by Brian Leathem (@bleathem) on CodePen.

Observable reduce

See the Pen Reduce an Observable by Brian Leathem (@bleathem) on CodePen.

zip

var outputData = Rx.Observable.zip(
  input1Data,
  input2Data,
  function(x1, x2) {
    return {
      id: x1.id
    , color: x1.color
    , size: x2.size
    , type: x2.type
    };
  });
Notes
  • The last function we’ll explore in such detail is the zip function

Observable zip

See the Pen Zip an Observable by Brian Leathem (@bleathem) on CodePen.

A Burgeoning Standard

Notes
  • At this point I want to point out that the Observable API is undergoing the standardisation process
  • So we you don’t have to worry that you are incorporating yet-another proprietary library in your code
  • Eventually, the Observable, in some future form, will be part of the official javascript language

Creating Observables

Brute Force:
var source = Rx.Observable.create(function (observer) {
  observer.onNext(42);
  observer.onCompleted();

  // Optional: only return this if cleanup is required
  return function () {
    console.log('disposed');
  };
});
Notes
  • So now that we know how to work with Observables, let’s take a step back and look at creating them
  • Here I’m showing the brute force approach for creating Observables
  • …​

Example: mousemove

Using the brute force approach:
Rx.Observable.create(function(observer) {
  var element = document.getElementById("box1");
  element.addEventListener("mousemove", function(event) {
    observer.onNext(event);
  }, false);
});
Notes
  • An example of this brute force approach for creating Observables is shown here
  • where we use an event listener to trigger observer events
  • this is however a naive implementation, as we really should take care of un-registering the listener when the observable is disposed of

Example: mousemove

Using the fromEvent helper
var element = document.getElementById("box1");
Rx.Observable.fromEvent(element, 'mousemove');
Notes
  • Fortunately we don’t often have to deal with such details, as the Rx.js library provides a number of helper methods for creating Observables

Consuming Observables

Rx.Observable.fromEvent(element, 'mousemove')
  .subscribe(
    function(event) {
      console.log(event);
    },
    function(error) {
      console.log(error);
    },
    function() {
      // stream completed
    }
Notes
  • We can create Observables, and we can manipulate them
  • The last piece of the puzzle we have to discuss is how to consume them
  • Observables don’t have any effect until we subscribe to the observable
  • You can think of the subscribe method as a forEach, where you are iterating over each object in the observable
  • In this code snippet we use a helper method to create a mousemove Observable, and then subscribe to it
  • in the subscribe method we specify 3 functions
    • an event iterator
    • an error handler
    • a completion callback

Learn Rx

http://reactive-extensions.github.io/learnrx/

Notes
  • At this point I would like to point you to the learnrx resource for learning and exercising your Rx.js knowledge
  • Unfortunately we don’t have the time to work through the tutorial, so we’ll move on as though we have the above concepts cemented in our heads
  • Let’s take a look at some use-cases, and see how manipulating Observables can give us some powerful functionality in a concise way

Use Case: jQuery .on()

Rx.Observable.fromEvent(element, 'mousemove')
  .filter(function(event) {
    return event.target.classList.contains('myClass');
  })
  .subscribe(...);

Example: jQuery .on()

See the Pen Event Listener by Brian Leathem (@bleathem) on CodePen.

Use Case: Drag and Drop

Define the Observables:
var dragTarget = document.getElementById('dragTarget');
var mouseup   = Rx.Observable.fromEvent(dragTarget, 'mouseup');
var mousemove = Rx.Observable.fromEvent(document,   'mousemove');
var mousedown = Rx.Observable.fromEvent(dragTarget, 'mousedown');

Use Case: Drag and Drop

Manipulate the Observables
var mousedrag = mousedown.flatMap(function (md) {
  var startX = md.offsetX, startY = md.offsetY;
  return mousemove.map(function (mm) {
    mm.preventDefault();
    return {
      left: mm.clientX - startX,
      top: mm.clientY - startY
    };
  }).takeUntil(mouseup);
});

Use Case: Drag and Drop

Subscribe to Observables
var subscription = mousedrag.subscribe(function (pos) {
  dragTarget.style.top = pos.top + 'px';
  dragTarget.style.left = pos.left + 'px';
});

Example: Drag and Drop

See the Pen Event Listener by Brian Leathem (@bleathem) on CodePen.

Hot and Cold

  • Hot Observable
    • Ongoing; event stream doesn’t stop
  • Cold Observable
    • No events until you subscribe
{...a...b...c......d..e.....f...}
{1...2...3......4..5.....6}
https://openclipart.org/detail/170672/weather-icon-hot https://openclipart.org/detail/170665/weather-icon-cold
Notes
  • Why do we need the takeUntil method the mousemove Observable?
  • One subtlety of Observables is they can be broken down into 2 types: cold and hot

Ending Observables

{...1.....2....3..4...5....}.take(3)

yields:


{1.....2....3}
Notes
  • the take and takeUntil methods then let us terminate Observables, allowing us to act on a well-defined set of values

Use Case: Autocomplete

Rx.Observable.fromEvent($input, 'keyup')
  .map(function (e) {
    return e.target.value; // Project the text from the input
  })
  .filter(function (text) {
    return text.length > 2; // Only if the text is longer than 2 characters
  })
  .debounce(750 /* Pause for 750ms */ )
  .distinctUntilChanged() // Only if the value has changed
  .flatMapLatest(searchWikipedia)
  .subscribe(function (data) {
    // ...
  });

Example: Autocomplete

See the Pen Event Listener by Brian Leathem (@bleathem) on CodePen.

Middleware Keynote demo

  • UI built with Rx.js (and d3.js)

Demo

Image references

Conclusion

Quite simply:

Rx.Js allows us to complex asynchronous applications as a composition of very simple functions

Resources