Will rxjs merge.complete() close subscriptions to all of its input streams?

Viewed 962

in below case will .pipe(takeUntil(this.unsubscribe)) close subscriptions to all of input streams?

protected unsubscribe: Subject<void>;

public ngOnDestroy(): void {
   this.unsubscribe.next();
   this.unsubscribe.complete();
}

merge(
  this.productsSelect.selected,
  this.productsSelect.removed,
  this.productsSelect.typed)
  .pipe(takeUntil(this.unsubscribe))
  .subscribe(() => {
    this.detectChanges();
  );
4 Answers

takeUntil will close the subscription when the observable passed into it receives a notification.

Take this example:

private destroyed$ = new Subject();
private sub: Subscription;

ngOnInit() {
  this.sub = merge(
    this.obs1(),
    this.obs2()
  ).pipe(
    takeUntil(this.destroyed$)
  ).subscribe(result => {
    console.log(result);
  }, () => {}, () => {
      console.log('complete');
  });
}

ngOnDestroy() {
  // this.sub is still open
  console.log(this.sub);

  // now close the subscription indirectly
  this.destroyed$.next();
  this.destroyed$.complete();

  // this.sub is now closed
  console.log(this.sub);
}

private obs1(): Observable<any> {
  return timer(0, 1000).pipe(mapTo('Hello, '));
}

private obs2(): Observable<any> {
  return timer(0, 1500).pipe(mapTo('World!'));
}

While the component is in the DOM, the two observables will continue to fire and the merge subscription will receive values from the timer observables.

When the component is removed from the DOM, ngOnDestroy will fire. The first console.log(this.sub) will show the subscription is open. The second will show it has been closed.

From the console:

Object { closed: false, ... }

Object { closed: true, ... }

DEMO: https://stackblitz.com/edit/angular-8c9nkd

Yes merge completes

Szenario

const finish$ = new Subject();
const source1$ = interval(200).pipe(mapTo('source 1'), takeUntil(finish$))
const source2$ = interval(210).pipe(mapTo('source 2'), takeUntil(finish$))
const source3$ = interval(220).pipe(mapTo('source 3'), takeUntil(finish$))

merge(
  source1$,
  source2$,
  source3$
).subscribe(
  (v) => console.info('next: ', v),
  (e) => console.error(e),
  () => console.warn('complete')
);

setTimeout(() => finish$.next(), 500);

Output:

next: source 1
next: source 2
next: source 3
next: source 1
next: source 2
next: source 3
complete

Stackblitz

rxjs-merge-complete

If I understand your question properly, then yes. The takeUntil operator will complete the Observable, so there will be no remaining subscriptions to inner Observables.

I dont think...

takeUntil must be able to send and receive.

you must do like this :

// declare into class
unsubscribe : Subject<any>;

// into constructor
this.unsubscribe = new Subject();

// into your method
merge(
  this.productsSelect.selected,
  this.productsSelect.removed,
  this.productsSelect.typed)
  .pipe(takeUntil(this.unsubscribe))
  .subscribe(() => {
    this.detectChanges();
);

ngOnDestroy(): void {
  this.unsubscribe.next();
  this.unsubscribe.complete();
}
Related