For more tips like this, sign up to the weekly newsletter!

RxJs first() vs take(1)

Given two observables, a typical scenario is to do something when the second observable emits after each emit from the first one.

For example, a drag-and-drop needs to handle the drop event for each mouseup that follows a mousedown.

One approach is to subscribe to the first observable and subscribe to the second one after each event.

The following code demonstrates this:

const trigger = new rxjs.Subject();
const events = new rxjs.Subject();

trigger.subscribe(() => {
  events.pipe(rxjs.operators.first()).subscribe(console.log.bind(console));
});

events.next(1);
events.next(2);
trigger.next();
events.next(3);	// Trigger
events.next(4);
trigger.next();
events.next(5);	// Trigger
trigger.next();

Using first() here is the trivial choice, as you are interested in the first event.

But when the event stream completes before emitting a single event, first() throws an error, which is not what you'd want.

Completing the stream can happen for a variety of reasons. For example, the server sent new data, and the draggable component is now removed.

To demonstrate this, let's add a complete() call to the events stream:

trigger.next();
events.next(1); // Trigger
trigger.next();
events.complete(); // Error

To avoid this issue, use take(1) instead of first(). It behaves the same in this situation but does not throw if the stream completes.

trigger.subscribe(() => {
  events.pipe(rxjs.operators.take(1)).subscribe(console.log.bind(console));
});

trigger.next();
events.next(1);	// Trigger
trigger.next();
events.complete(); // No error
Try it
References
Learn more: