blog

  • Home
  • blog
  • 10 Need-to-Know RxJS Functions with Examples

10 Need-to-Know RxJS Functions with Examples

As the interest in functional reactive programming (FRP) has grown, RxJS has emerged as one of the most popular JavaScript libraries for programming in this paradigm. In this article, we’re going to take a look at what I consider to be the ten must-know functions from RxJS.

Note: This article presupposes familiarity with the basics of RxJS, as presented in the article Introduction to Functional Reactive Programming with RxJS.

Reactive Programming

Reactive programming is a programming paradigm that treats streams of data, called Observables, as its basic units of programming.

Streams—or Observables , in RxJS jargon—are analogous to event listeners: Both wait for something to happen, and notify you when it does. The series of asynchronous notifications you get from an onClick listener is a perfect example of a stream of data.

Put another way, an Observable is nothing more than an array that populates over time.

That array’s elements can come from just about anywhere: The file system, DOM events, API calls, or even converted synchronous data, like arrays. At heart, reactive programming is nothing more than using Observables as the building blocks of your programs.

Relationship to arrays

Arrays are simple because their contents are final unless explicitly changed. In that sense, there’s nothing essentially temporal about an array.

An Observable, on the other hand, is defined by time. The most you can know about a stream is that it has received [1, 2, 3] so far. You can’t be certain that you’ll ever get a 4—nor that you won’t—and it’s the data source, not your program, that decides.

The relationship between streams and arrays is so profound that most of the reactive extensions derive from the world of functional programming, where list operations are bread and butter.

Warming up to RxJS

Consider the all-too-common to-do app. Let’s see how the problem of displaying only the names of a user’s incomplete tasks looks with RxJS:

const task_stream =
  // Makes a stream of all the tasks in the database
  getTasks().
    // Get tasks only for this user
    filter((task) => task.user_id == user_id).
    // Get tasks that are incompleted
    filter((task) => !task.completed).
    // Only get name of task
    map((task) => task.name)

/* Tasks look like this:
   task = {
    user_id   : number,
    completed : boolean,
    name      : string
   }
 */

So far, this is nothing more than array extras, but demonstrates reactive programming’s functional flavor.

It’s declarative nature becomes clear with the addition of more complicated, “real-world” features. Let’s say we want to:

  • Kick off the request in response to the user’s selection to view either complete or incomplete tasks;
  • Only send a request for the last selection every second, so as not to waste bandwidth if the user quickly changes their choice;
  • Retry failed requests up to three times; and
  • Only redraw the view when the server sends a different response from last time.
const task_stream =
  parameter_stream.
    debounce(1000).
    map((parameter) => {
      getTasks().
        retry(3).
        filter((task) => task.user_id === user_id).
        filter((task) => task.completed === parameter).
        map((task)    => task.name)
    }).
    flatMap(Rx.Observable.from).
    distinctUntilChanged().
    update()

Step by step:

  • parameter_stream tells us whether the user wants complete or incomplete tasks, storing the choice in parameter;
  • debounce() ensures we only pay attention to the last button click every second;
  • The section around getTasks() does the same as before;
  • distinctUntilChanged() ensures we only pay attention when the server’s response is different than it was last time; and
  • update() takes care of updating the UI to reflect what we got from the server.

Handling debounce, retry, and “distinct until changed” logic in an imperative, callback-based style is valid, but it can be both brittle and complicated.

The takeaway is that programming with RxJS allows for:

  1. Declarative programs;
  2. Extensible systems; and
  3. Straightforward, robust error-handling.

We’ll meet each of the functions in the above example on our tour through the ten must-know functions of RxJS.

Operations on Simple Streams

The fundamental functions on simple streams—those that emit simple values, like strings—include:

With the exception of take() and takeWhile(), these are analogous to JavaScript’s higher-order array functions.

We’ll apply each of these by solving an example problem: Finding all the users in our database who have a .com or .org website, and calculating the average length of their websites’ names.

JSONPlaceholder will be our source of users. Here’s the JSON representation of the user data we’ll be working with.

1. Using map() to transform data

Using map() on an Observable is identical to using it on an array. It:

  1. Accepts a callback as an argument;
  2. Executes it on every element of the array you called it on; and
  3. Returns a new array with each element of the original array replaced with the result of calling the callback on it.

The only differences when using map() on Observables are that:

  1. Instead of returning a new array, it returns a new Observable; and
  2. It executes every time the Observable emits a new item, instead of immediately and all at once.

We can use map() to transform our stream of user data into just a list of their website names:

Continue reading %10 Need-to-Know RxJS Functions with Examples%

LEAVE A REPLY