Tutorial hero
Lesson icon

Subscribe flow in RxJS

Originally published September 29, 2022 Time 3 mins

Since we were dealing with complex RxJS streams in the video for this week, I thought it would be worthwhile to give a little extension of that here.

(You should probably watch the video for some context first, otherwise this will be harder to follow)

When dealing with more complex streams that use multiple operators, it becomes more important to understand the flow of what is actually happening with piped operators.

The most natural way to think about it is probably that we start with our data at the top, and it flows downwards through all the piped operators, and comes out at the end having being modified somehow:

cheat sheet in terminal

In the diagram above, I am using parenthesis to indicate a stream. For example ([1, 2, 3]) is a stream that emits a single array. Whereas (1, 2, 3) is a stream that emits 1, then 2, then 3.

In this case, that means our mental model would be something like:

  1. Take the photos from the currentPhotos stream
  2. Return a stream that emits one photo at a time
  3. Each time one photo is emitted, create a new stream of just that one photo
  4. Delay that stream by some amount
  5. Once that stream completes (having been delayed) the concatMap can move on to the next emission from the stream returned by the switchMap

This is an accurate way to think of the data flow in a stream - the data gets passed down along the chain of piped operators as each stream emits data.

But, I think it is also useful to understand how the flow of subscriptions work. Rather than flowing downwards, the subscriptions flow upwards.

subscriptions flowing upwards

Let’s consider what actually happens when we subscribe to the currentPhoto stream in the image above.

What we are actually subscribing to is whatever the last operator inside of the currentPhoto pipe method returns. This stream only has two operators: switchMap and concatMap. We are ignoring the nested piped operators for now (I have coloured these differently to differentiate them).

The concatMap operator is last, so when we call subscribe on our currentPhoto stream, we are subscribing to the observable returned by that concatMap.

That operator will then subscribe to the operator above it, and takes its values from there. That means that our concatMap operator will subscribe to the observable returned from our switchMap operator.

Finally, our switchMap operator will then subscribe to the source stream which is our currentPhotos stream.

…but wait…

We’ve skipped an important chunk here. We mentioned that since the last operator is concatMap, that is what we are subscribing to when we subscribe to the currentPhoto stream.

But, the observable that concatMap returns also uses its own piped operators. The exact same thing is happening here, within one level of nesting.

When we subscribe to the observable returned by concatMap, we are actually subscribing to its own last operator, which in this case is delayWhen. That’s actually the only operator, but if there were more, delayWhen would subscribe to the operators above it and so on until the first operator subscribes to the source observable, which is of(photo) in this case.

We can continue in this way for as many levels of nested pipes as we have.

Learn to build modern Angular apps with my course