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.










share|improve this question






















  • 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















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.










share|improve this question






















  • 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













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.










share|improve this question













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






share|improve this question













share|improve this question











share|improve this question




share|improve this question










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


















  • 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












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).






share|improve this answer























  • Impressive ShortLivedObservable concept, but sticking it permanently with switchMap may limit use cases. Still, worth consideration.
    – Tomas
    Nov 9 at 10:29




















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






share|improve this answer





















    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














     

    draft saved


    draft discarded


















    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

























    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).






    share|improve this answer























    • Impressive ShortLivedObservable concept, but sticking it permanently with switchMap may limit use cases. Still, worth consideration.
      – Tomas
      Nov 9 at 10:29

















    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).






    share|improve this answer























    • Impressive ShortLivedObservable concept, but sticking it permanently with switchMap may limit use cases. Still, worth consideration.
      – Tomas
      Nov 9 at 10:29















    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).






    share|improve this answer














    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).







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Nov 9 at 9:56

























    answered Nov 9 at 9:44









    ggradnig

    2,200317




    2,200317












    • 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


















    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














    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






    share|improve this answer

























      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






      share|improve this answer























        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






        share|improve this answer












        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







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 9 at 7:54









        Tomas

        868917




        868917






























             

            draft saved


            draft discarded



















































             


            draft saved


            draft discarded














            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





















































            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