What is the difference between tap and map in RxJS?

A mapping function takes a thing and returns another thing. e.g. I can build a function that takes 10 and returns 11, that takes 11 and returns 12, etc.

const inc = n => n + 1;

Array#map applies such mapping function to all elements of an array but "map" doesn't mean "iteration".

In RxJS, when a data is sent to the stream it goes through a series of operators:

  • The map operator will simply apply a function to that data and return the result.
  • The tap operator however takes a data, apply a function to that data but returns the original data, if the function bothered to return a result, tap just ignores it.

Here's an example:

  • We push 10 to stream a$, tap just log the value. We know that console.log always return undefined but that's fine because tap simply returns its parameter.
  • We push 10 to stream b$, it goes through map(inc) which applies inc to 10 returning 11.

const a$ = of(10).pipe(tap(n => console.log(`tap: ${n}`)));
const b$ = of(10).pipe(map(inc));

a$.subscribe(n => console.log(`n from a$: ${n}`));
b$.subscribe(n => console.log(`n from b$: ${n}`));
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.5/rxjs.umd.min.js"></script>

<script>
const {of} = rxjs;
const {map, tap} = rxjs.operators;

const inc = n => n + 1;
</script>

  • The purpose of tap is to execute an action keeping the same value of the observable

  • The purpose of map is to transform the emitted values of the observable

const messagesCount$ = newMessages$
.pipe(tap(messages => notificationService.notify('You have ' + message.length + ' message(s)')))
.pipe(map(messages => messages.length))

Tap should be Used for Notification, logging non-contextual/critical side effects.

It's like a "peek" into the "pipe". The data stays the same, You can do something with it. Some data goes in, you look, same data comes out.

Map is for transformation/mapping of the Data in the "pipe". Some data comes in, different/transformed data comes out.

Tags:

Rxjs