Understanding takeUntil

takeUntil forwards every emission from the source observable to the observer until a second observable, called the notifier, produces its first value. The operator sets up subscriptions to both streams at the same time. As soon as the notifier fires, takeUntil tears down both subscriptions and sends a complete signal to the observer. In the case where the notifier never emits anything yet runs to completion, takeUntil simply lets all source values through without interruption.

Keep in mind that when you want to limit the count of emissions from a source, the take operator is the right choice instead.

Here is how the operator behaves step by step:

  1. Initiate subscriptions to the source observable and the notifier observable
  2. Forward each source emission to the observer as it arrives
  3. When the notifier emits any value, unsubscribe from both streams and deliver the complete notification to the observer
  4. If the source finishes naturally, deliver the complete notification to the observer
  5. If the source throws an exception, pass the error notification along to the observer

Typical Use Cases

The primary purpose of takeUntil is to prevent memory leaks and to clean up active subscriptions when a particular condition becomes true. In architecture built around components, it is common to trigger takeUntil when a component is destroyed, using a notifier observable that signals that event. The notifier is frequently implemented as a Subject.

Consider the following example that illustrates this pattern:

const stream = interval(1000);

function component(source) {
   const notifier = new Subject();

   source.pipe(
       takeUntil(notifier)
   ).subscribe(render);

   return () => {
       notifier.next(null);
   };
}

const destroy = component(stream);

setTimeout(destroy, 3000);

function render(v) {
   const text = document.createTextNode(v);
   document.body.appendChild(text);
}

Interactive Demo

Further Reading