Как уже упоминалось, нет никакого способа сделать вывод исключительно по типу Observable
, будет ли он завершен в любой момент в будущем или нет.Контракт Observable не включает такую семантику.Тем не менее, я мог бы представить следующие решения:
1: разрешить кому-то другому обрабатывать отписку
Я считаю хорошей практикой не связываться с подпиской или отпиской, когда я не являюсь конечным потребителемнаблюдаемого.Под конечным потребителем я подразумеваю компонент, который в конечном итоге использует уведомления, например, для отображения данных.
Вместо того, чтобы подписываться и отписываться, я использую трубку Angular async
как можно чаще.В большинстве случаев преобразование данных может быть обработано с помощью Observable pipes
таким образом, что все мои промежуточные компоненты просто добавляют каналы, и только компонент представления в конце концов подписывается на результат Observable.Если ваша структура представления еще не поддерживает это, я бы попытался найти плагин или даже реализовать его сам.
Например, вместо того, чтобы присваивать результат наблюдаемого свойству класса, как в вашем примере,Я бы просто использовал шаблон 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>
2: введите новый тип
Хотяисходный наблюдаемый контракт не включает семантику для решения вашей проблемы, мы могли бы ввести собственный тип, который будет заключен в 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: Избегание takeUntil Leaks ).