'What is the difference between tap and map in RxJS?

I read the difference from the article but the main points look like this.

so with tap I can change the variables such as that if I put x=3+4 then it changes the values of variable then I can say there is one side effect.

But with map I can change the value looping each value, isn't it? Can you pinpoint what outstanding differences they have?

tap

RxJS tap performs side effects for every value emitted by source Observable and returns an Observable identical to the source Observable until there is no error.

map

map is a RxJS pipeable operator. map applies a given function to each element emitted by the source Observable and emits the resulting values as an Observable



Solution 1:[1]

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>

Solution 2:[2]

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.

Solution 3:[3]

The tap and map are both RxJS operators, RxJS operators are just function that performs some manipulation over the data.

Both of them are pipeable operators which takes input as Observable, perform some action and return an output observable.

Difference between map and tap:

The map is a pipeable operator that takes an input observable, performs some manipulation on it and returns a new manipulated observable. For example

const source$ = of(1,2,3) // observable which will emit 1,2,3
// It take an input observable and return a new observable which will emit square of input values. 
// So, the output observable will emit 1,4,9
const mapSource$ = of(1,2,3)
                    .pipe(map(value => value * value)) 

The tap operator on another hand takes an input observable perform some action and returns the same input observable.

const source$ = of(1,2,3) // observable which will emit 1,2,3
// It take an input observable and return a same observable after console value.
// So, the output observable will emit 1,2,3
const tapSource$ = of(1,2,3)
                    .pipe(tap(value => console.log(value))) 

Solution 4:[4]

  • 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))

Solution 5:[5]

you can think of tap operator as a void function that whatever it does to the input value it does not change the original value

const source = of(1, 2, 3, 4, 5);

// here we are manipulating the input value but the output value of the observable still the same 
const example = source.pipe(
  tap(val => val + 100),
);

// output: 1, 2, 3, 4, 5
const subscribe = example.subscribe(val => console.log(val));

in the other hand if we made any manipulation of the input values of the observable using the map operator it will change the output values

const example = source.pipe(
  map(val => val + 100)
);

// output: 101, 102, 103, 104, 105
const subscribe = example.subscribe(val => console.log(val));

Solution 6:[6]

I addition to what the others are saying, in Rxjs 7.4 tap now has three more subscribe handlers, so you can use it to get notified on subscribe, unsubscribe and finalize:

https://github.com/ReactiveX/rxjs/commit/eb26cbc4488c9953cdde565b598b1dbdeeeee9ea#diff-93cd3ac7329d72ed4ded62c6cbae17b6bdceb643fa7c1faa6f389729773364cc

This is great for debugging purposes, so you can use tap to find out much more about what is happening with your stream.

Example:

const subscription = subject
.pipe(
  tap({
    subscribe: () => console.log('subscribe'),
    next: (value) => console.log(`next ${value}`),
    error: (err) => console.log(`error: ${err.message}`),
    complete: () => console.log('complete'),
    unsubscribe: () => console.log('unsubscribe'),
    finalize: () => console.log('finalize'),
  })
)
.subscribe();

Solution 7:[7]

TAP, can NOT transform:

interval(1000).pipe(tap(el=> el*2)).subscribe(console.log); // 0,1,2,3

MAP, CAN transform:

interval(1000).pipe(map(el=> el*2)).subscribe(console.log); // 0,2,4,6

If you do NOT need to transform the value, just console.log it or run external function to pass the Original value = TAP is good.

If you NEED TO TRANSFORM/CHANGE the value = MAP is the way to go.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 customcommander
Solution 2 customcommander
Solution 3 Jasdeep Singh
Solution 4 customcommander
Solution 5 redd77
Solution 6 Sámal Rasmussen
Solution 7 fruitloaf