Determine if Observable is “completable”
up vote
0
down vote
favorite
I often facing a situation, where I can't determine easily if the observable is "completable" or not. What I mean under completable? Let say we have:
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
);
}
...
In our service.ts we have method getData(), which returns data, through Observable and after that it completes.
Why I want to know if it completes? Because if it completes, it means I don't need to unsubscribe from that after my component gets destroyed. Obviously in trivial cases it doesn't matter that much, but if you are working in teams on a large codebase, you every time need to figure it out.
rxjs
add a comment |
up vote
0
down vote
favorite
I often facing a situation, where I can't determine easily if the observable is "completable" or not. What I mean under completable? Let say we have:
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
);
}
...
In our service.ts we have method getData(), which returns data, through Observable and after that it completes.
Why I want to know if it completes? Because if it completes, it means I don't need to unsubscribe from that after my component gets destroyed. Obviously in trivial cases it doesn't matter that much, but if you are working in teams on a large codebase, you every time need to figure it out.
rxjs
Do you have an example of an observable that doesn't complete? I'm afraid this is impossible due to the Halting problem en.wikipedia.org/wiki/Halting_problem
– ShamPooSham
Nov 9 at 7:48
For e.g. if I'm listening for key or mouse events.
– Gabriel
Nov 9 at 7:51
Yeah, I think that's impossible due to the halting problem. Sorry
– ShamPooSham
Nov 9 at 7:52
There is no mechanism through which an observable can advertise to potential subscribers whether or not it completes.
– cartant
Nov 9 at 9:08
add a comment |
up vote
0
down vote
favorite
up vote
0
down vote
favorite
I often facing a situation, where I can't determine easily if the observable is "completable" or not. What I mean under completable? Let say we have:
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
);
}
...
In our service.ts we have method getData(), which returns data, through Observable and after that it completes.
Why I want to know if it completes? Because if it completes, it means I don't need to unsubscribe from that after my component gets destroyed. Obviously in trivial cases it doesn't matter that much, but if you are working in teams on a large codebase, you every time need to figure it out.
rxjs
I often facing a situation, where I can't determine easily if the observable is "completable" or not. What I mean under completable? Let say we have:
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
);
}
...
In our service.ts we have method getData(), which returns data, through Observable and after that it completes.
Why I want to know if it completes? Because if it completes, it means I don't need to unsubscribe from that after my component gets destroyed. Obviously in trivial cases it doesn't matter that much, but if you are working in teams on a large codebase, you every time need to figure it out.
rxjs
rxjs
asked Nov 9 at 7:41
Gabriel
1,33732247
1,33732247
Do you have an example of an observable that doesn't complete? I'm afraid this is impossible due to the Halting problem en.wikipedia.org/wiki/Halting_problem
– ShamPooSham
Nov 9 at 7:48
For e.g. if I'm listening for key or mouse events.
– Gabriel
Nov 9 at 7:51
Yeah, I think that's impossible due to the halting problem. Sorry
– ShamPooSham
Nov 9 at 7:52
There is no mechanism through which an observable can advertise to potential subscribers whether or not it completes.
– cartant
Nov 9 at 9:08
add a comment |
Do you have an example of an observable that doesn't complete? I'm afraid this is impossible due to the Halting problem en.wikipedia.org/wiki/Halting_problem
– ShamPooSham
Nov 9 at 7:48
For e.g. if I'm listening for key or mouse events.
– Gabriel
Nov 9 at 7:51
Yeah, I think that's impossible due to the halting problem. Sorry
– ShamPooSham
Nov 9 at 7:52
There is no mechanism through which an observable can advertise to potential subscribers whether or not it completes.
– cartant
Nov 9 at 9:08
Do you have an example of an observable that doesn't complete? I'm afraid this is impossible due to the Halting problem en.wikipedia.org/wiki/Halting_problem
– ShamPooSham
Nov 9 at 7:48
Do you have an example of an observable that doesn't complete? I'm afraid this is impossible due to the Halting problem en.wikipedia.org/wiki/Halting_problem
– ShamPooSham
Nov 9 at 7:48
For e.g. if I'm listening for key or mouse events.
– Gabriel
Nov 9 at 7:51
For e.g. if I'm listening for key or mouse events.
– Gabriel
Nov 9 at 7:51
Yeah, I think that's impossible due to the halting problem. Sorry
– ShamPooSham
Nov 9 at 7:52
Yeah, I think that's impossible due to the halting problem. Sorry
– ShamPooSham
Nov 9 at 7:52
There is no mechanism through which an observable can advertise to potential subscribers whether or not it completes.
– cartant
Nov 9 at 9:08
There is no mechanism through which an observable can advertise to potential subscribers whether or not it completes.
– cartant
Nov 9 at 9:08
add a comment |
2 Answers
2
active
oldest
votes
up vote
1
down vote
accepted
As mentioned, there is no way to infer solely by the type of Observable whether it will complete at any future point in time or not. The Observable Contract does not include such semantics. However, I could imagine the following solutions:
1: Let someone else handle unsubscribing
I found it a good practice to not get involved with subscribing or unsubscribung when I'm not the final consumer of the Observable. By final consumer I mean the component that is ultimately using the notifications to e.g. display data.
Instead of subscribing and unsubscribing myself, I use the Angular async pipe as often as possible. In most instances, transformation of data can be handled with Observable pipes, in a way that all my intermediate components just add pipes and just the view component finally subscribes to the result Observable. If your view framework does not support this yet, I would try to find a plugin or even implement it myself.
For example, instead of assigning the result of the observable to a class property, like in your example, I'd just use the Angular template to subscribe to the Observable. The component is modified:
public data$: Observable<number>;
public updateData(): void {
// here, modification would take place with pipes
this.data$ = this.serviceA.getData();
}
And finally in the template, I'd use async:
<div *ngIf="(data$ | async) as data">
{{ data }}
<div>
2: Introduce a new type
Although the original observable contract does not include semantics for dealing with your issue, we could introduce an own type that wraps around an Observable to indicate that this observable will complete eventually. To guarantee this behaviour, we could add a timeout that completes the observable if it hasn't notified for a given time. It could look like this:
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)
)
}
However, this solution would come with the drawback, that new semantics are introduced that don't follow the ReactiveX practices. The type would have to be passed on to the final consumer and further piping could make the observable leaky again (see issues described here: RxJS: Avoiding takeUntil Leaks).
ImpressiveShortLivedObservableconcept, but sticking it permanently withswitchMapmay limit use cases. Still, worth consideration.
– Tomas
Nov 9 at 10:29
add a comment |
up vote
1
down vote
In my opinion the good practice is to consider all observables as ever-lasting and never "complitable". There is no direct way of determining a priori is particular observable "complitable" because this is entirely up to observable logic, which from user perspective is private and belongs to observable. Instead of doing assumptions it's better to store each subscription in controller variable and when controller get's destroyed just unsubscribe to all of them, which is safe even for already closed subscriptions.
If you have specific actions to do on observable completeness, try to implement it in onComplete handler.
This approach forces you to consider all below edge scenarios:
- no value will be emitted and observable will complete (empty)
- no value will be emitted and observable will not complete (empty ever-lasting)
- infinite amount of values will be emitted and observable will not complete (ever-lasting)
- one or more value will be emitted and observable will be completed
add a comment |
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
1
down vote
accepted
As mentioned, there is no way to infer solely by the type of Observable whether it will complete at any future point in time or not. The Observable Contract does not include such semantics. However, I could imagine the following solutions:
1: Let someone else handle unsubscribing
I found it a good practice to not get involved with subscribing or unsubscribung when I'm not the final consumer of the Observable. By final consumer I mean the component that is ultimately using the notifications to e.g. display data.
Instead of subscribing and unsubscribing myself, I use the Angular async pipe as often as possible. In most instances, transformation of data can be handled with Observable pipes, in a way that all my intermediate components just add pipes and just the view component finally subscribes to the result Observable. If your view framework does not support this yet, I would try to find a plugin or even implement it myself.
For example, instead of assigning the result of the observable to a class property, like in your example, I'd just use the Angular template to subscribe to the Observable. The component is modified:
public data$: Observable<number>;
public updateData(): void {
// here, modification would take place with pipes
this.data$ = this.serviceA.getData();
}
And finally in the template, I'd use async:
<div *ngIf="(data$ | async) as data">
{{ data }}
<div>
2: Introduce a new type
Although the original observable contract does not include semantics for dealing with your issue, we could introduce an own type that wraps around an Observable to indicate that this observable will complete eventually. To guarantee this behaviour, we could add a timeout that completes the observable if it hasn't notified for a given time. It could look like this:
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)
)
}
However, this solution would come with the drawback, that new semantics are introduced that don't follow the ReactiveX practices. The type would have to be passed on to the final consumer and further piping could make the observable leaky again (see issues described here: RxJS: Avoiding takeUntil Leaks).
ImpressiveShortLivedObservableconcept, but sticking it permanently withswitchMapmay limit use cases. Still, worth consideration.
– Tomas
Nov 9 at 10:29
add a comment |
up vote
1
down vote
accepted
As mentioned, there is no way to infer solely by the type of Observable whether it will complete at any future point in time or not. The Observable Contract does not include such semantics. However, I could imagine the following solutions:
1: Let someone else handle unsubscribing
I found it a good practice to not get involved with subscribing or unsubscribung when I'm not the final consumer of the Observable. By final consumer I mean the component that is ultimately using the notifications to e.g. display data.
Instead of subscribing and unsubscribing myself, I use the Angular async pipe as often as possible. In most instances, transformation of data can be handled with Observable pipes, in a way that all my intermediate components just add pipes and just the view component finally subscribes to the result Observable. If your view framework does not support this yet, I would try to find a plugin or even implement it myself.
For example, instead of assigning the result of the observable to a class property, like in your example, I'd just use the Angular template to subscribe to the Observable. The component is modified:
public data$: Observable<number>;
public updateData(): void {
// here, modification would take place with pipes
this.data$ = this.serviceA.getData();
}
And finally in the template, I'd use async:
<div *ngIf="(data$ | async) as data">
{{ data }}
<div>
2: Introduce a new type
Although the original observable contract does not include semantics for dealing with your issue, we could introduce an own type that wraps around an Observable to indicate that this observable will complete eventually. To guarantee this behaviour, we could add a timeout that completes the observable if it hasn't notified for a given time. It could look like this:
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)
)
}
However, this solution would come with the drawback, that new semantics are introduced that don't follow the ReactiveX practices. The type would have to be passed on to the final consumer and further piping could make the observable leaky again (see issues described here: RxJS: Avoiding takeUntil Leaks).
ImpressiveShortLivedObservableconcept, but sticking it permanently withswitchMapmay limit use cases. Still, worth consideration.
– Tomas
Nov 9 at 10:29
add a comment |
up vote
1
down vote
accepted
up vote
1
down vote
accepted
As mentioned, there is no way to infer solely by the type of Observable whether it will complete at any future point in time or not. The Observable Contract does not include such semantics. However, I could imagine the following solutions:
1: Let someone else handle unsubscribing
I found it a good practice to not get involved with subscribing or unsubscribung when I'm not the final consumer of the Observable. By final consumer I mean the component that is ultimately using the notifications to e.g. display data.
Instead of subscribing and unsubscribing myself, I use the Angular async pipe as often as possible. In most instances, transformation of data can be handled with Observable pipes, in a way that all my intermediate components just add pipes and just the view component finally subscribes to the result Observable. If your view framework does not support this yet, I would try to find a plugin or even implement it myself.
For example, instead of assigning the result of the observable to a class property, like in your example, I'd just use the Angular template to subscribe to the Observable. The component is modified:
public data$: Observable<number>;
public updateData(): void {
// here, modification would take place with pipes
this.data$ = this.serviceA.getData();
}
And finally in the template, I'd use async:
<div *ngIf="(data$ | async) as data">
{{ data }}
<div>
2: Introduce a new type
Although the original observable contract does not include semantics for dealing with your issue, we could introduce an own type that wraps around an Observable to indicate that this observable will complete eventually. To guarantee this behaviour, we could add a timeout that completes the observable if it hasn't notified for a given time. It could look like this:
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)
)
}
However, this solution would come with the drawback, that new semantics are introduced that don't follow the ReactiveX practices. The type would have to be passed on to the final consumer and further piping could make the observable leaky again (see issues described here: RxJS: Avoiding takeUntil Leaks).
As mentioned, there is no way to infer solely by the type of Observable whether it will complete at any future point in time or not. The Observable Contract does not include such semantics. However, I could imagine the following solutions:
1: Let someone else handle unsubscribing
I found it a good practice to not get involved with subscribing or unsubscribung when I'm not the final consumer of the Observable. By final consumer I mean the component that is ultimately using the notifications to e.g. display data.
Instead of subscribing and unsubscribing myself, I use the Angular async pipe as often as possible. In most instances, transformation of data can be handled with Observable pipes, in a way that all my intermediate components just add pipes and just the view component finally subscribes to the result Observable. If your view framework does not support this yet, I would try to find a plugin or even implement it myself.
For example, instead of assigning the result of the observable to a class property, like in your example, I'd just use the Angular template to subscribe to the Observable. The component is modified:
public data$: Observable<number>;
public updateData(): void {
// here, modification would take place with pipes
this.data$ = this.serviceA.getData();
}
And finally in the template, I'd use async:
<div *ngIf="(data$ | async) as data">
{{ data }}
<div>
2: Introduce a new type
Although the original observable contract does not include semantics for dealing with your issue, we could introduce an own type that wraps around an Observable to indicate that this observable will complete eventually. To guarantee this behaviour, we could add a timeout that completes the observable if it hasn't notified for a given time. It could look like this:
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)
)
}
However, this solution would come with the drawback, that new semantics are introduced that don't follow the ReactiveX practices. The type would have to be passed on to the final consumer and further piping could make the observable leaky again (see issues described here: RxJS: Avoiding takeUntil Leaks).
edited Nov 9 at 9:56
answered Nov 9 at 9:44
ggradnig
2,200317
2,200317
ImpressiveShortLivedObservableconcept, but sticking it permanently withswitchMapmay limit use cases. Still, worth consideration.
– Tomas
Nov 9 at 10:29
add a comment |
ImpressiveShortLivedObservableconcept, but sticking it permanently withswitchMapmay limit use cases. Still, worth consideration.
– Tomas
Nov 9 at 10:29
Impressive
ShortLivedObservable concept, but sticking it permanently with switchMap may limit use cases. Still, worth consideration.– Tomas
Nov 9 at 10:29
Impressive
ShortLivedObservable concept, but sticking it permanently with switchMap may limit use cases. Still, worth consideration.– Tomas
Nov 9 at 10:29
add a comment |
up vote
1
down vote
In my opinion the good practice is to consider all observables as ever-lasting and never "complitable". There is no direct way of determining a priori is particular observable "complitable" because this is entirely up to observable logic, which from user perspective is private and belongs to observable. Instead of doing assumptions it's better to store each subscription in controller variable and when controller get's destroyed just unsubscribe to all of them, which is safe even for already closed subscriptions.
If you have specific actions to do on observable completeness, try to implement it in onComplete handler.
This approach forces you to consider all below edge scenarios:
- no value will be emitted and observable will complete (empty)
- no value will be emitted and observable will not complete (empty ever-lasting)
- infinite amount of values will be emitted and observable will not complete (ever-lasting)
- one or more value will be emitted and observable will be completed
add a comment |
up vote
1
down vote
In my opinion the good practice is to consider all observables as ever-lasting and never "complitable". There is no direct way of determining a priori is particular observable "complitable" because this is entirely up to observable logic, which from user perspective is private and belongs to observable. Instead of doing assumptions it's better to store each subscription in controller variable and when controller get's destroyed just unsubscribe to all of them, which is safe even for already closed subscriptions.
If you have specific actions to do on observable completeness, try to implement it in onComplete handler.
This approach forces you to consider all below edge scenarios:
- no value will be emitted and observable will complete (empty)
- no value will be emitted and observable will not complete (empty ever-lasting)
- infinite amount of values will be emitted and observable will not complete (ever-lasting)
- one or more value will be emitted and observable will be completed
add a comment |
up vote
1
down vote
up vote
1
down vote
In my opinion the good practice is to consider all observables as ever-lasting and never "complitable". There is no direct way of determining a priori is particular observable "complitable" because this is entirely up to observable logic, which from user perspective is private and belongs to observable. Instead of doing assumptions it's better to store each subscription in controller variable and when controller get's destroyed just unsubscribe to all of them, which is safe even for already closed subscriptions.
If you have specific actions to do on observable completeness, try to implement it in onComplete handler.
This approach forces you to consider all below edge scenarios:
- no value will be emitted and observable will complete (empty)
- no value will be emitted and observable will not complete (empty ever-lasting)
- infinite amount of values will be emitted and observable will not complete (ever-lasting)
- one or more value will be emitted and observable will be completed
In my opinion the good practice is to consider all observables as ever-lasting and never "complitable". There is no direct way of determining a priori is particular observable "complitable" because this is entirely up to observable logic, which from user perspective is private and belongs to observable. Instead of doing assumptions it's better to store each subscription in controller variable and when controller get's destroyed just unsubscribe to all of them, which is safe even for already closed subscriptions.
If you have specific actions to do on observable completeness, try to implement it in onComplete handler.
This approach forces you to consider all below edge scenarios:
- no value will be emitted and observable will complete (empty)
- no value will be emitted and observable will not complete (empty ever-lasting)
- infinite amount of values will be emitted and observable will not complete (ever-lasting)
- one or more value will be emitted and observable will be completed
answered Nov 9 at 7:54
Tomas
868917
868917
add a comment |
add a comment |
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53221596%2fdetermine-if-observable-is-completable%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Do you have an example of an observable that doesn't complete? I'm afraid this is impossible due to the Halting problem en.wikipedia.org/wiki/Halting_problem
– ShamPooSham
Nov 9 at 7:48
For e.g. if I'm listening for key or mouse events.
– Gabriel
Nov 9 at 7:51
Yeah, I think that's impossible due to the halting problem. Sorry
– ShamPooSham
Nov 9 at 7:52
There is no mechanism through which an observable can advertise to potential subscribers whether or not it completes.
– cartant
Nov 9 at 9:08