tap / do

signature: tap(nextOrObserver: function, error: function, complete: function): Observable

Transparently perform actions or side-effects, such as logging.


💡 If you are using and old version of RxJS, tap used to be known as do!


Why use tap?

Think of tap as a surveillance camera in a shopping mall. It doesn't interfere with the shoppers (values) moving around but merely observes and records their actions. This operator is best for side effects: actions you want to take in response to values in an observable, without affecting the values themselves.

One of the superpowers of tap is its utility in debugging. When things aren't going as planned with your observable, instead of tearing apart your chain or inserting numerous logs, simply sprinkle in some tap operators. It's like adding checkpoints in a video game, helping you swiftly pinpoint issues without disrupting the main flow.

However, a word of caution: remember that tap is solely for side effects. If you find yourself tempted to modify data within a tap, it's generally best to resist. That's not its purpose, and you're better off with map or other transformational operators in these cases.

Lastly, it's best to ensure that the side effects you introduce via tap are not critical to the main logic of your observable chain, keeping them non-intrusive and harmless.

Examples

Example 1: Logging with tap

( StackBlitz | jsBin | jsFiddle )

// RxJS v6+
import { of } from 'rxjs';
import { tap, map } from 'rxjs/operators';

const source = of(1, 2, 3, 4, 5);
// transparently log values from source with 'tap'
const example = source.pipe(
  tap(val => console.log(`BEFORE MAP: ${val}`)),
  map(val => val + 10),
  tap(val => console.log(`AFTER MAP: ${val}`))
);

//'tap' does not transform values
//output: 11...12...13...14...15
const subscribe = example.subscribe(val => console.log(val));

Example 2: Using tap with object

( StackBlitz)

// RxJS v6+
import { of } from 'rxjs';
import { tap, map } from 'rxjs/operators';

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

// tap also accepts an object map to log next, error, and complete
const example = source
  .pipe(
    map(val => val + 10),
    tap({
      next: val => {
        // on next 11, etc.
        console.log('on next', val);
      },
      error: error => {
        console.log('on error', error.message);
      },
      complete: () => console.log('on complete')
    })
  )
  // output: 11, 12, 13, 14, 15
  .subscribe(val => console.log(val));

Additional Resources


📁 Source Code: https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/tap.ts

Last updated