关于使用“ 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()(请参见上面的代码)?
谢谢。
答案 0 :(得分:2)
1)如果希望取消API调用,则它必须是可观察链的一部分。当在subscribe
内部执行呼叫时,无法取消它,因此您必须为此使用诸如mergeMap
或concatMap
之类的运算符。
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()
,因为下一条通知将使该链失效。