Functional Reactive Programming explained in a simple way, in JavaScript…yes, in a simple way.

Eric Rey
ITNEXT
Published in
7 min readJun 20, 2018

--

If you have come to this article, in order to understand it, you should be familiar with JavaScript, should have an understanding of what Reactive Programming (RP) is, as well as what Functional Programming (FP) is; you don’t have to master either of them though, and hopefully you will be able to leave with a clearer understanding of what Functional Reactive Programming (FRP) is about.

The reason I wanted to write this article is that after looking on the internet about FRP, almost everything I found were RP articles and examples that claimed to be FRP but they had nothing done in the “functional way”. There seems to be a lot of confusion; developers writing about FRP, a great deal of the time are just chaining operators with dot notation to transforms streams, instead of chaining pure functions by using pipe, something that’s core to FP. If you did not understand the last sentence, don’t worry, explaining it is the whole point of this article.

Let’s forget about FRP and RP for a second and let’s see the difference between the traditional imperative and the declarative ways of programming. For this I’ll first code in the way most of us have been coding in JavaScript for a while and then I’ll use FP. This will refresh your mind if you have seen FP before, but are a little rusty and it will help you understand the transition from RP to FRP, and why the two terms don’t mean the same thing. I’m going to try to keep the examples simple so they are easy to reason about, but granted, to fully understand this article you need to be familiar with RP and FP.

The problem:

You have a variable holding an array of strings and your task is to take each string, trim it, convert it to upper case and then print the new resulting array to the browser console.

We will never modify the original array and we will be using the following two variables throughout the article. Other than that, I’ll be repeating the code we need in each example so you have the complete snippets and can follow along even if you are on your phone and don’t have an IDE or a Code Editor at hand.

Traditional imperative way:

We have used a for loop and we have chained the methods trim and toUpperCase, nothing fancy and something like that code we probably see every day.

A declarative way:

Now we have created two variables in a way we can reuse and we have used the Array.prototype.map method to accomplish our goal. You probably noticed that by solving the problem this way we have been inefficient because we have traversed the array twice, first to trim the values and then to convert them to upper case. I know you are not going to sleep well tonight if we leave it like that and neither am I; so let’s do something about it.

Improving inefficiency:

We can feel better, there is no inefficiency now. If you are thinking that the for loop in the first example performs better and is faster than the map function, I suggest you take a look at this great presentation https://www.youtube.com/watch?v=g0ek4vV7nEA, I promise, it will change your mind.

If you are a FP advocate, or at least you like what it promotes, you will feel that something does not look right and you will think there is a way to do better. There is indeed something else we can do if we are leaning to a more functional approach anyway.

Since you are familiar with FP, you at least know the idea behind the pipeAll variable, but I will talk a little bit about it anyway. Array.prototype.reduce applies a function against an accumulator and each element in the array (from left to right) to reduce it to a single value, as per https://developer.mozilla.org/, so if you wanted to sum up all the elements in an array you could do something like this:

In our case, the elements contained in our array will not be numbers, they will be functions, like trim and toUpperCase and all those functions will be executed by passing into each of them the result returned by the previous function, for each value in the words array. It’s like if all those functions made a pipe, and each word were to pass through it and at the end, it will be already trimmed and converted to upper case. If you still don’t understand, you should probably see examples about using reduce and read an article that has the purpose of properly and thoroughly explaining how it works, trust me, it’ll be worth your while.

You can find implementations like pipeAll (the name is actually pipe) in libraries like Rambda, https://ramdajs.com/. I wanted to include the implementation in this code and not use Rambda so you can see what’s happening without going anywhere else, and the only reason I called pipeAll instead of pipe was so it would not conflict with the pipe pure function you will see in the Reactive Programming section.

Now we have the flexibility to “pipe” as many functions as we want, which gives us a high degree of flexibility to compose functions and we don’t even have to create a variable like trimAndUpperCase, we can just inline map with pipeAll like this:

Now our code has a declarative new look and we can go even further by creating our own version of map bycurrying” it, using the curry method from Rambda. Then we would be able to remove the dot notation in that previous line of code, but I think that would be going too far for the purpose of this article. One more thing, this is not really pure functional code because we are accessing the words variable, which is not locally scoped to a pure function and because we are writing to the browser console, but we don’t have to be so strict in this article, achieving total purity is not our goal.

Next I will show a simple RP example where the problem is almost the same, but with a slight variation (so we see the “reactive way”). Once the user clicks a button on the page that has assigned the css class “myButton”, we have to stream the values in the words array but already trimmed and converted to upper case and print them to the browser console. We are going to be using version 5.5.11 of the RxJS library, so feel free to add a script tag pointing to https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.11/Rx.min.js.

Reactive Programming:

I know you already told me you are familiar with RP, but if you don’t quite remember what flatMap does, you can read this great article written by David Wilson: https://medium.com/@w.dave.w/becoming-more-reactive-with-rxjs-flatmap-and-switchmap-ccd3fb7b67fa.

That’s RP, and after seeing how we got to functional code previously in this article, I hope this last code example does not look functional to you at all. In fact, RxJS 5 introduced several pure functions that are the ones that allow us to do FRP.

Using let and the new pure functions to be more functional:

Here we have used map and pipe, the RxJS version of them, which operate in the same way you saw before in this article. So even if you are new to FRP, this code should still make sense and that was the reason I took you through that transitional path at first, so taking your mental model from RP to FRP would be easier.

We can be more functional than this. Let’s look at the last code example:

We have refactored the code in a way we are also “piping” flatMap, along with trim and toUpperCase, and we got rid of the trimAndUpperCase variable. Hopefully, by now, you will be able to differentiate RP from FRP, and if you are, I will be feeling happy because that means I would have accomplished my goal.

If you are like me, when you see new technologies or approaches or paradigms, you wonder if you can build important, big, maintainable, reusable and scalable systems with them, and you are wondering if you can do it with Reactive Programming, in general, I recommend you watch this very interesting presentation: https://www.youtube.com/watch?v=XRYN2xt11Ek. Spoiler, RP powers most of the development infrastructure at Netflix, on both client and server side, and that should answer your question.

Happy coding!

--

--

Software Engineer — Tech Lead @ AWS. Functional Programming advocate.