Information is King — tap() — how to console.log in RxJS
We all know and love the mighty console.log
. Every time we need to see certain value at certain stage of our function we eagerly put it in every other line. How can we achieve such behavior in the RxJS world of Observables?
The tap() operator
Here comes the tap()
operator. It does not influence the Observable stream in any way and just passes all notifications through without modifying them. You might ask why would we use such operator if it does not do anything? It can be used to provide side-effects at any stage of the operators pipeline, which is what we need if we want to spy on our Observable and see what happens inside.
Let’s consider the following code:
This puts our, let’s call it, spy inside of this Observable’s pipeline. Each time some value passes through the filter()
operator, it will get logged to the console just before the value reaches the map()
operator. This is very useful for debugging, and also learning about Observable streams.
Where can I put it?
You can put the tap()
operator at any stage of the pipeline.
For example, if you put it as the first one:
It will receive the same exact notifications that will be emitted by the source, which in our case is someObservable$
.
If you put it at the end:
The logged values will be exactly the same as those which reach the function inside of the subscribe()
call at the end.
Handling other notification types
In the above examples we just console.logged
the emitted values.
The values in RxJS are emitted by using ‘next’ notifications. The Observables can also emit other notification types such as ‘error’ or ‘complete’. The tap()
operator can also react to those. To do so, you need to provide an object containing handlers for the notification types you want to handle:
You do not need to provide handlers for all notification types. You can choose just the ones that you need and omit the rest.
One more thing…
Starting from RxJS 7.3.0, the tap()
operator can do even more. You can see when the Subscription starts and ends at the level of the tap()
operator.
On top of the ‘next’, ‘error’ and ‘complete’ handlers which we have discussed above, the tap()
operator introduces three more handlers:
- subscribe — called when a new Subscription is made,
- unsubscribe — called when the Subscription is closed by unsubscribing (calling
unsubscribe
); this will NOT be executed when ‘error’ or ‘complete’ is emitted, - finalize — called when the Subscription ends, no matter what the cause: it can be either unsubscribing, an error or a complete notification; all will cause the ‘finalize’ handler to be called.
Example usage:
Remember that those callbacks are executed by thetap()
operator, so these handlers will be executed by the notifications and Subscription events that happen at the level of the tap()
operator — not the whole Subscription.
To show you what I mean, let me show you this example:
In the above example, we can track when the Subscriptions made by the switchMap()
operator are created and ended.
As you can see, within one Observable there can happen a lot of inner Subscriptions and the tap()
operator can help us track and learn how it all happens and when.
Conclusion
The tap()
operator can act as a debugging tool in the RxJS world just as our favorite friend — console.log
did in the regular JavaScript universe. In fact, the tap()
operator allows us to put the console.log
calls inside of the pipeline of operators and spy on the emitted values and other notifications. Also, we can spy and track the Subscriptions as they come and go at any stage of the pipeline. All these features are a great way not only to debug but also learn how things work in RxJS!
Thank you for reading! If you have enjoyed this article please give it a clap and follow me (Medium, Twitter, LinkedIn) to see more stuff like this.
I know that the tap()
operator allows much more than debugging and adding console.logs
. Let me know how do you use the tap()
operator in the comments section! As a bonus, have a go in the Stackblitz playground below and try the tap()
operator on your own!
New to RxJS?
If you are new to RxJS or would like to polish your knowledge, I invite you to have a look at my RxJS and Observables: Introduction course.