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