简体   繁体   中英

Why a 'next' before 'complete' of Angular takeuntil ngUnsubscribe?

There are tons of info out there on using 'takeUntil' operator to unsubscribe from a stream, like so:

 ... export class CategoryOptionInputComponent constructor(private svc: MyService, protected router: RouterService) { ... this.router.routerUrl$.pipe(takeUntil(this.ngUnsubscribe)).subscribe(s => { const param1 = s.state.featureId; this.svc.InitFromApi(param1); }); ... } ngOnDestroy() { this.ngUnsubscribe.next();//<-- This line is confusing this.ngUnsubscribe.complete(); } private readonly ngUnsubscribe = new Subject(); }

As the above code shown, we needed to load data from API on router data being parsed, and continue to load new data when new router data arrives, until the component is destroyed.

When a user navigating to a different route, the component is expected to be destroyed without a last hit on the API. However it does not behave as expected. The call to API is made even if the component is about to be destroyed.

My questions are:

(1) How to prevent the component to hit the API before it dies?

(2) Why not just complete() the stream, why a next() call before complete() (see the above code)?

Thanks ahead.

1) If you want the API call to be cancelable it needs to be part of the observable chain. When the call is performed inside subscribe there's no way it can be canceled so you'll have to use an operator for this such as mergeMap or concatMap .

this.router.routerUrl$.pipe(
  takeUntil(this.ngUnsubscribe),
  concatMap(s => {
    const param1 = s.state.featureId;
    return this.svc.InitFromApi(param1);
  })
).subscribe();

However, this expects that this.svc.InitFromApi() returns an Observable or a Promise. If you subscribe inside InitFromApi() or use then() on a Promise then it makes in unsubscribable.

2) That's how takeUntil is designed. It only reacts to next notifications. If you don't want to call both next() and complete() you can use defaultIfEmpty() operator:

this.router.routerUrl$.pipe(
  takeUntil(this.ngUnsubscribe.pipe(
    defaultIfEmpty(null),
  ))
).subscribe(...);

Then you can call just this.ngUnsubscribe.complete() it'll trigger takeUntil as well.

Actually, in your example you don't even need to call complete() if you call next() because the next notification will make the chain to dispose.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM