我经常遇到这样的情况,即我无法轻松确定可观察对象是否“可填充”。我所说的“完成”是什么意思?假设我们有:
service.ts
...
public getData(): Observable<number[]> {
// Obviously in real application there would be something more meaningful
return of([1, 2, 3]);
}
...
component.ts
...
public updateData(): void {
this.serviceA.getData.subscribe(
newData => this.data = newData
);
}
...
在我们的service.ts
中,我们有方法getData()
,该方法通过Observable
返回数据,并在完成后返回数据。
为什么我想知道它是否完成?因为它完成了,这意味着在我的组件被销毁之后,我不需要取消订阅。显然,在微不足道的情况下,这没什么大不了的,但是如果您在大型代码库中的团队中工作,则每次都需要弄清楚它。
答案 0 :(得分:1)
在我看来,优良作法是将所有可观察到的事物视为永恒且永不“复杂”。没有直接的方法可以确定先验是特定的可观察的“可简化的”,因为这完全取决于可观察的逻辑,从用户的角度来看,这是私有的并且属于可观察的逻辑。与其进行假设,不如将每个订阅存储在控制器变量中,并且当控制器被销毁时,只需取消订阅所有订阅,这对已关闭的订阅也是安全的。
如果您要针对可观察到的完整性执行特定操作,请尝试在onComplete
处理程序中实现它。
这种方法迫使您考虑以下所有边缘情况:
答案 1 :(得分:1)
如前所述,没有办法仅凭Observable
的类型推断它是否会在将来的任何时间点完成。 Observable Contract不包含此类语义。但是,我可以想象以下解决方案:
我发现,当我不是Observable的最终用户时,不参与订阅或取消订阅是一种很好的做法。最终消费者是指最终使用通知的组件,例如显示数据。
我尽可能地使用Angular async
管道来代替自己的订阅和退订。在大多数情况下,可以使用Observable pipes
处理数据的转换,这样,我所有的中间组件都只会添加管道,而只有view组件最终会订阅结果Observable。如果您的视图框架尚不支持此功能,我将尝试找到一个插件,甚至自己实现。
例如,我没有像您的示例那样将observable的结果分配给class属性,而是仅使用Angular模板来订阅Observable。该组件已修改:
public data$: Observable<number[]>;
public updateData(): void {
// here, modification would take place with pipes
this.data$ = this.serviceA.getData();
}
最后在模板中,我将使用async
:
<div *ngIf="(data$ | async) as data">
{{ data }}
<div>
尽管原始的可观察合同不包含处理您的问题的语义,但是我们可以引入一个自己的类型,该类型将Observable
括起来以表明该可观察对象最终将完成。为了保证这种行为,我们可以添加一个超时,如果在给定时间内没有通知,则该超时将使可观察的事件完成。看起来可能像这样:
class ShortLivedObservable<T> extends Observable<T> {
private constructor() {
super();
}
}
function asShortLivedObservable<T>(source: Observable<T>, timeout: number = 1000): ShortLivedObservable<T> {
return source.pipe(
switchMap(value =>
merge(
of(value).pipe(
map(value => ({value: value}))
),
timer(timeout).pipe(
map(() => ({complete: true}))
)
)
),
takeUntil(({value, complete}) => complete),
map(({value}) => value)
)
}
但是,此解决方案将带来缺点,即引入了不遵循ReactiveX惯例的新语义。该类型将必须传递给最终使用者,并且进一步的管道传输可能再次使可观察到的泄漏(请参阅此处描述的问题:RxJS: Avoiding takeUntil Leaks)。