6

In a lot of codebases using RxJS I seem to come across the pattern of exposing private Subjects as Observables via a getter or normal getObservable() function. My question is not why .asObservable() is used, but instead why it seems so commonly wrapped in a getter/factory function?

asObservable() wrapped in getter/factory function


private readonly _engineInfo$ = new Subject<EngineInfo>();
get engineInfo$() { return this._engineInfo$.asObservable(); }

asObservable() as instance variable


private readonly _engineInfo$ = new Subject<EngineInfo>();
public engineInfo$ = this._engineInfo$.asObservable();

Questions


  • My undestanding is that .asObservable() creates a new Observable every time that subscribes to the Subject. Also the created Observable is hot and can be subscribed multiple times. Why would one create multiple anonymous instances of Observable, (one for each access/subscription), instead of having just one Observable, accessed at one class/service, that all observers subscribe to?
  • Is there a non-obvious advantage to this getter/factory function pattern?
  • Could it be because of garbage collection or testing/mocking advantages?

So far I'm using the instance variable setup from the second example in all services/classes and everything seems to works as expected, also with multiple observers.

timmwagener
  • 2,368
  • 2
  • 19
  • 27
  • 2
    I must say, this is the first time I've ever heard of the getter factory pattern being considered as a commonly used pattern for observables. I assume the 2 suit different use cases and I would choose the one that suits you best. – Kurt Hamilton Apr 18 '20 at 11:32
  • I just called it a "pattern", since literally in every RxJS/Angular codebase (at my company) it seems to be the canonical way to access observables of subjects. So I assumed it must be quite popular, best practice and have some reason....!? Could you elaborate on the different use cases you mentioned? Why would you ever want a new `Observable` instance in practice as opposed to add another subscription to one central hot `Observable`? – timmwagener Apr 18 '20 at 12:39
  • I don't know! I would just reuse a single observable instance. – Kurt Hamilton Apr 18 '20 at 12:55
  • Subject IS an Observable, there is no need to perform such conversion. The code above can be used to disable calling `subject.next(something)` – Yevhenii Dovhaniuk Apr 18 '20 at 14:31
  • 1
    Asking "_Why....?_" questions here is a risky business because they can easily be seen as inviting opinions, but I don't think that is the case for this question which has been carefully worded to invite technical arguments rather than opinion. Voting to reopen. – skomisa Apr 18 '20 at 21:20
  • I've also seen implementation like the first one with "get new instance" using getter and my question is also the same: "Why would one create multiple anonymous instances of Observable". Are we fine with that or should we use a solution with single instance of Observable, like the second implementation suggests? – minus one Jan 24 '22 at 17:30

1 Answers1

2

When to use Subject.prototype.asObservable()

The purpose of this is to prevent leaking the "observer side" of the Subject out of an API. Basically to prevent a leaky abstraction when you don't want people to be able to "next" into the resulting observable.

You never want to return a Subject instance to the calling context. Doing so would be somewhat akin to returning a Deferred object rather than a promise; and, it would leave the Subject open to unanticipated and corrupting usage. As such, when exposing a Subject, you'll probably want to convert it to an Observable first.

To get this working we can use the Rx.Observable.prototype.asObservable()instance method.

The subject itself is hot/sharable and it acts as a bridge/proxy between the source Observable and many observers, making it possible for multiple observers to share the same Observable execution.

Is there a non-obvious advantage to this getter/factory function pattern?
Nope, not at all since you are Creating a new Observable with this Subject as the source to conceal it from code that uses the Observable.

When to use asObservable() in rxjs?

Vikas
  • 11,859
  • 7
  • 45
  • 69
  • 4
    thanks for your detailed answer! It may have been a little too detailed though, since, as stated in the orig. question, i'm aware of why/when to use `.asObservable()`. The main point of the question was to uncover if there is any use wrapping it up in `getter/factory functions` so that every client gets a new `Observable`, as opposed to every client subscribing to the same `Observable`. You answer that too, but not very prominently at the end. If you consider making this part more prominent, i would possibly upvote your answer. _(Not yet accept though, in case something comes up)_. – timmwagener Apr 19 '20 at 10:03
  • I think, instead of using a getter, using a read only instance _piped_ by `shareReplay(1)` (https://www.learnrxjs.io/learn-rxjs/operators/multicasting/sharereplay) can do the job. I got the idea from https://www.gushiciku.cn/pl/2dLx – nelson6e65 Jun 11 '21 at 08:43
  • Ok, no advantage. Is there some disadvantage, or are any other concerns using multiple instances of Observables? – minus one Jan 24 '22 at 17:36