Skip to content
This repository was archived by the owner on May 2, 2020. It is now read-only.

bitspook/frp-with-rxjs-jschannel-conf

Repository files navigation

Functional Reactive Programming with RxJS

This is a reveal.js presentation. I created the presentation at slides.com, and then imported it to reveal.js for inserting my example scripts inside the presentation (slides.com won’t allow that). To check it out locally, just open the index.html file.

http://img.youtube.com/vi/SFPF56BB1Cs/0.jpg

What follows below is the transcript of the presentation.

Intro

For next few minutes we’ll discuss Functional Reactive Programming inspired development in Javascript. We’ll discus how FRP can help us write asynchronous code much more declaratively, how it improves the quality of our code in general etc.

But before we start digging into FRP, I wanna say few words of in loving memory of my friend Coyote.

A story of Coyote

Coyote was a software developer,

always chasing javascript like all of us. He never could though, like most of us.

One day, he was a given a task. To “Render tweets to a web page”. “Can’t be a task simpler than this”, he said. To start with the solution, he assumed that he has an array of 100 or so tweets, and a tweet looks like this:

var tweets = [{
  id: 'tweet1',
  username: 'koyote',
  body: 'I will finally catch you :3'
}
.
.
.
(100 or so)];

Fare assumption I think.

Being an awesome developer, Coyote has drafted out his specs very clearly. His sub-tasks are:

  • only show the tweets from the logged-in user
  • only show the tweets with a specific hash-tag
  • and replace the text emogies with images. Emogies are those little smilies kids put all over their texts.

So he start with the code, one problem at a time

var tweets = getTweets();
tweets
    .filter(t => t.username === me.username)
  • He gets his tweets from the source, and for his first task he uses filter. Filter is a nice “Array extra” method on ES5 arrays, which takes a function, run it on each item of the array, and create a new array with those items for which the given function returns true. Note here we’re using ES6 fat-arrow syntax. It’s same thing as creating an anonymous function; when we don’t use braces, it returns the single statement. so
    x => x * 2;
        

    is same as:

    function(x) { return x * 2; }
        

    Now he need to traverse the tweets again, to keep only those tweets which has the selected hash-tag. You guessed it, another filter. This time his fitler uses an even higher order function.

    .filter(t => hasTag(selectedHTag, t.text) )
        
  • Now for next task, he need to manipulate each tweet, and replace the text emogies in it’s text with <img> tags. For that he uses another array extra method, map.
    .map(t => {
          t.text = emogize(t.text);
          return t;
      })
        

    Map is similar to filter in that it takes a function, it apply that function to each item of the array, and returns a new array of the processed values.

  • For the last nail in the coffin, he uses `forEach` to traverse each item in his processed collection of tweets, and render each tweet.
    .forEach(t => render);
        

Coyote is too proud now, and rightfully so. His code looks good.

tweets
  .filter(t => t.username === me.username)
  .filter(t => t.text.split(' ').includes(selectedHTag))
  .map(t => {
    t.text = emogize(t.text);
    return t;
  })
  .forEach(t => render);

His code has no dangling state around.

It’s composed of small independent units of logic, and is still composable.

And best of all, his code is not mutating the source data. In map, he manipulates the tweets but without risking any modification of the source `tweets` variable.

The system Coyote has built works somewhat like this.

http://i.imgur.com/1wMthve.png The data source is made to go through an operation, and the result is passed to a sink for side-effects. The Operations in this case is special that it won’t mutate the source, and it doesn’t depend on any external state. Given same input, it will always produce same output. In other words it is a pure function. Beauty of pure functions is that they can be composed to make complex operations without any hassle. Each operation Coyote used is a pure function.

This functional approach bring a lot of value to the code.

First very important thing it do is that it make the code very readable. Just laying your eyes on the code explains everything it is doing. You can absorb it in chunks. There’s no state to keep in mind.

Lesser cognitive load means more maintainable code. You won’t be afraid to touch this code in future if you need to. There is lot less chance of breaking something with changing one part of your code.

Pure functions are super easy to test. The easiest to test I would say.

Modular compos-able code means ease of extension. Want to introduce new behavior? Just drop in new operation. For example, Coyote’s code render each tweet one at a time. A better approach would be to combine all the tweets and render them all at once. Doing that is just a matter of introducing a `reduce` before render `forEach`.

Using purer functions this way encourage reusability. For example the `hasTag` and `emogize` in Coyote’s case. Doing things the functional way induces DRY code.

But, this is Javascript.

The reality bumps in and it is not pretty. Turns out the source is asynchronous, it produces one tweet at a time. Coyote’s heart sunk when his project manager shows up with the eventual surprise. Asynchronous code in Javascript. Hmmm. Sounds familiar? I wonder what options Coyote had.

First thing that came in his mind was callbacks. Now callbacks are cute.

So cute cringe

Here, eye bleach if your eyes are bleeding already.

  • Problems with callbacks are real though. First thing that come to mind is composability. How would he compose callbacks? Remember how Coyote used small operations to accomplish the greater good? Good luck doing that with callbacks.
  • Dangling state can be nasty, very nasty with callbacks. Imagine yourself 6 level deep in callbacks. 5th callback uses something set by 2nd callback. Now debug.
  • Readability is the first thing to get murdered. I can feel you QA people.
  • Dangling state, hard to read, I think it explains the rest.

Or he can use Promise.

The slayer of callbacks and savior of peasants. Now promises are awesome. Callbacks treated async data as bastard child of Javascript for ages, thanks to promises async values can be passed around like regular data. But Promises are not free of all evil. For one, they are hard to compose. They resolve once at most and then be done with it, and canceling a promise in a pool of asynchronous requests is not the something you’d do on a sunny weekend. What Coyote wanted was something that would provide brevity of functional programming along with all the awesomeness we saw with the synchronous version.

So may be it’s time to make a compromise?

Coyote lived a life of no compromise. He won’t compromise, not even in face of callbacks. Frustrated by his helplessness, Coyote stood straight and jumped out of his window, on 10th floor. Right before the fall, windows reminded Coyote of another awesome product from his favorite company, which always gave him awful products.

No not Acme.

Microsoft has this awesome project called RxJS.

RxJS brings C#’s reactive extensions to Javascript, and quite beautifully too.

Great thing is, Rx has alternatives for many different programming languages. Learn once implement everywhere is the trend, right?

But it was too late for Coyote. Poor Coyote.

Never mind. It’s not late for us though. Let’s use RxJS to fulfill Coyote’s falling wish.

How would the code look if we write it using RxJS?

var tweets_ = Rx.Observable.fromPromise(getTweets);

tweets_
  .filter(t => t.username === me.username)
  .filter(t => hasTag(selectedTag) )
  .map(t => {
    t.text = emogize(t.text);
    return t;
  })
  .subsribe(x => render(x));

Umm…shit. Have I copied the same synchronous code here? I think I’ve made a mistake. What if I haven’t though? What if that Observable is a magical unicorn that allow you to use Array extras on asynchronous values? haha…day dreams.

Let’s take a look at the code again. Here’s the synchronous version, when we had an array.

And the code which might be true.

Turns out, it is no mistake. It is valid code. Observable is the unicorn that could have saved Coyote another painful fall.

Observable

Say hello to the unicorn in the room. Observable is one of many ways of representing asynchronous values in Javascript, two of which we checked earlier. It is a lot like a Promise, but acts more like a collection of asynchronous values.

They are the building blocks of FRP inspired programming using RxJS. Almost everything is an Observable, or a derivative of it.

They are first class async values, like a promise is.

Plus, they have a large number of operators that allow composing operations the same way as we did with arrays.

And they play well with other form of data that you might have. We’ll see how later. Before we dive into Observables, let me answer first why you should care. I mean of course Observables are awesome and you should be using them, but so are pure functions, but how many really care?

  • Observables are proposed to be made first-class citizens in ES7. Promises are native in ES6, and Observables, hopefully will be in ES7.
  • Angular 2 gets away from its infamous digest loop by using Observables for change detection. So yea, first class support for them in Angular 2.
  • And the new hot thing (react) has plans to support Observables first class. Or so I’ve heard.

Alright then, let’s address the elephant in the room. Or was it unicorn? Elephant sized unicorn perhaps. You can think of an Observable, as an array spanned over time. It gets its values in future, and may or may not finish.

Programming for a large part is about manipulation of data. And how do we represent data in our day-to-day imperative programming? In variables, as values.

However, we rarely think of time as a factor in our code. Although it makes a lot of sense to think in terms of time for asynchronous programming. Let’s say if we do consider time in our code, we’ll call it temporal programming.

Now it’s same as imperative programming, I just made a term. What would be equivalent of a value in temporal programming? Something which don’t have a value yet, but it might have it in future. A promise.

But value and promise are singular representations of data. What’s the plural of a value? An iterable, arrays in ES5. That’s how we treat our data mostly, in collections, not in single values.

Now what is equivalent of an Iterable in temporal programming? Array of Promises is the wrong answer. It has to be an asynchronous collection, which don’t have all the values yet, which will get values over time in future. Plural of Promise, is an Observable. Observable in RxJS aim to mimic the interface of Array extras.

So if you know how to use Array extras, the map/reduce/filter, you already know how to use an Observable. Observable are pretty different from Arrays though. For instance, you can’t go back in an Observable. You can only get values from future. There are ways to keep old values though, but that’s different. Observables have more in common with Promises. I think of Observable as a Promise which can resolve more than once, and can tell when it is done. Observable are in my opinion, natural evolution of Promises.

So if Promise is Bulbasore, Observable is,

well,

evolved Bulbasore.

Enough about the manipulation of Observable with array-extra like interface, how do we actually put Observable to use. I mean if it’s evolution of Promise, and it is asynchronous, it would have success/fail callbacks, right? It does have it. resolve/reject and then/error of promises are called `onNext` and `onError` in Observable. And Observable is a collection, so it has to complete at some point. For that it has `onCompleted` callback too. These three callbacks can be put as a single unit,

called a `Observer`.

I didn’t talk about Observer till now, but it is important. Observer and Observable together makes the building blocks of all of RxJS. Now how Observer is important and why I didn’t talk about it till now. Turns out, you don’t need to create an Observer in most cases, you can just pass 1, 2 or 3 functions to an Observable’s subscribe method, and RxJS will implicitly create an observer for you. How Observer are important.

Observable are lazy. This code will not execute even when users_ Observable is supposed to get a value from a hot source.

let users_ = getUsersObservable();

let notJohnConners_ =
  users_
    .map(user => user.fullName)
    .map(name => name.first + ' ' + name.last)
    .filter(x => x === 'John Connor');

I used the term loosely. Observable are lazy in that they don’t execute the chain of operators, until there is an Observer subscribed to them. So this code will execute, only after we subscribe to it. This is a quite useful feature actually.

notJohnConners_.subscribe(
 (user) => console.log('New user arrived: ', user),
 (error) => console.log('Error Occured', error),
 () => console.log('All Done')
)

So in this example, `users_` is the Observable, `subscribe` will attach an Observer to it, what are map and filter? They are called Operators.

Operators allow doing different operations on Observables, to transform, merge, and coordinate Observable streams in whatever way you like. There’s a large number of operators available.

Plenty of them.

For everything you need. These are not all, there are more.

You can convert almost anything to an Observable. For example from

  • Variables or arrays
  • or Promises. Promises actually have great support in RxJS. Most of the time, you don’t need to convert a promise, you can just use them in place of Observable. RxJS do the conversion implicitly.
  • Even events. This is a great feature for cleaning up your UI code, we’ll see why it’s so great later.
  • We can even convert the functions which take callbacks to return Observable.
  • ES6 generators have great support in RxJS. You can convert a generator to Observable, or use it directly as a Promise.

I said we can convert events to Observable. But event listeners are may be the most common source of memory leaks. How do we tell an Observable to stop listening to an event? When we subscribe to an Observable, it creates a disposable object, on which we can call .dispose method, to tell it to release all the clean-up it need. But what is even better, you don’t need to explicitly call `dispose` in many cases. You can declaratively do the cleanup, get rid of event-listeners etc. Let’s see an example how.

var clicks_ = Rx.Observable.fromEvent(countBtn, 'click'),
    counter_ = Rx.Observable.from([1,2,3,4,5,6,7,8,9,10]);

var disposeable = clicks_
    .zip(
        counter_,
        function(e, count) { return count; }
    )
    .take(5)
    .subscribe(function(x) {countNode.innerHTML = x;});

Here I converted ‘click’ event on count button to observable, and I zipped it with another simple Observable so I get a number on every click. Not the `take` operator, it says that take exactly and only 5 values form this Observable; after that this Observable is not required. It is not required so it gets rid of it, and clean-up all the event-listeners it set up for it.

Let’s check it out. Second thing I wanted to show is the co-ordination of Observable. The `counter_` in this case will get all its values immediately. Like you create it from array, and it gets all its values right then. But, clicks_ will get a value only when user do a click, God knows when he’ll do it. RxJS handles all the co-ordination required between two asynchronous sources, and provides us the expected behavior at no expense of code readability or elegance.

RxJS has pretty good performance. They make a lot of efforts to keep footprint of the Observable object as small as possible. Another thing that help in performance, and give you more control over your asynchronous code is the swappable concurrency. Now Javascript is not concurrent, but we can chose how to put our async callbacks; on setImmediate, or on requestAnimationFrame for smooth animations, or we can even write our own scheduler. We won’t talk about them today. Oh wait, we just did. Eh, whatever. Rx makes smart decisions to provide fastest way to execute the code.

Unlike arrays, Observable don’t create intermediate sequences.

For each map/filter operation on an Array, a new array is created which than need to be discarded immediately. No such thing for Observable, so, yay, less work for garbage collector.

To make things better, RxJS support transducers, so we can even save ourselves from creating intermediate Observable.

And it plays very well with existing libraries you might be using. We can use Jquery or zepto events and promises etc.

There are framework bindings available for most frameworks. So you can start converting your existing apps without much hassle.

Oh, and it’s from Microsoft. So it has support up to IE6.

Examples

Time for some examples I guess. We are short on time, so let’s just quickly walk through them. Todo Examples

Conclusion

I noticed some happy things happening in my code when I started using RxJS more in my hoby projects.

I usually start my projects as a monilith, that do a very simpler version of the product. Then when I am implementing more things, I start modularising it as I see fit. While writing code the FRP way, I found modularising the code was so much more easier. Code was already modular. Converting the monolith was mostly a matter of moving the Observables to right places, clean up the API and done.

You saw in the mouse-follow example, we converted mouse-move to left and top observables. Now if we have to add another “eyes” widget to our app, that’ll be looking at the mouse all the time, we can simply reuse those two Observable. Not that we can’t do it with imperative code, but Observables make them so much more obvious, I’d say it encourage reuseability.

And of course the code is easy to read. That is a huge plus for someone like me who follow up the hobby projects at weeks distance sometime.

And I got all this by default. I said these were the happy side-effects I noticed in my code when I started using RxJS.

I guess we can conclude that writing FRP inspired code with RxJS or any other library that suits your taste bring us following benefits.

  • It help us write composable, simple code, which is easy to test
  • and easy to read
  • It is mostly stateless and composed of purer functions, so it is much more maintainable
  • I didn’t talk about error handling in RxJS, but it is another one of its killer features. In my opinion, error handling is what gives Rx an upper hand over CSP based systems.

In 4 words, elegent declarative code.

Elegent declarative asynchronous code. Well, it’s called asynchronous for a reason.

Thank you everyone.

About

Functional Reactive Programming in Javascript with RxJS : JsChannel Conf 2015

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published