为什么在ngUnsubscribe的“完成”之前“下一个”?

时间:2019-01-14 00:14:01

标签: angular rxjs

关于使用“ takeUntil”运算符从流中退订的信息很多,像这样:

...

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();
  
}

如上面的代码所示,我们需要从正在解析的路由器数据上的API加载数据,并在新的路由器数据到达时继续加载新数据,直到组件被破坏为止。

当用户导航到其他路线时,预计该组件将被销毁而不会在API上造成最后的打击。但是,它的行为不符合预期。即使该组件即将被销毁,也会调用API。

我的问题是:

(1)如何防止组件在死亡之前访问API?

(2)为什么不仅仅完成()流,为什么要在complete()之前调用next()(请参见上面的代码)?

谢谢。

1 个答案:

答案 0 :(得分:2)

1)如果希望取消API调用,则它必须是可观察链的一部分。当在subscribe内部执行呼叫时,无法取消它,因此您必须为此使用诸如mergeMapconcatMap之类的运算符。

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

但是,这期望this.svc.InitFromApi()返回一个Observable或Promise。如果您在InitFromApi()内进行订阅或在Promise上使用then(),则无法订阅。

2)takeUntil就是这样设计的。它仅对next通知作出反应。如果您不想同时调用next()complete(),则可以使用defaultIfEmpty()运算符:

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

然后,您可以只调用this.ngUnsubscribe.complete(),它也会触发takeUntil

实际上,在您的示例中,如果您调用complete(),甚至不需要调用next(),因为下一条通知将使该链失效。