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

若如初见. 提交于 2019-12-07 23:20:59

问题


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:


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.



来源:https://stackoverflow.com/questions/54174424/why-a-next-before-complete-of-angular-takeuntil-ngunsubscribe

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!