Urigo / meteor-rxjs

Exposing Mongo Cursor as RxJS Observable

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Understanding the expected behaviour of MeteorObservable.call()

cubitworx opened this issue · comments

I was wondering if there was a particular reason that MeteorObservable.call() is implemented using Observer.create()?

I would like to make multiple subscriptions to the observable returned by MeteorObservable.call(). However, doing this causes the function passed to Observable.create(subscribe: Function) inside MeteorObservable.call() to be called each time the Observable.subscribe() method is called. This means that the Meteor.call() method gets called several times instead of just once. Is this the intended behaviour & if so:

  1. Is there a specific reason it was done like this? Just so that I can better understand it & learn from it.
  2. Might this scenario be reason enough to implement it as a BehaviorSubject so that it is only ever called once & can still cater for 1 subscription? It would not be backward compatible for those who are currently relying on the fact that the Meteor.call() is only made when Observable.subscribe() is called.

I realise that I could just wrap the MeteorObservable.call() in my own observer to accomplish this but I was just surprised to find that the method was being called each time I subscribed to the observable; and thought it was worth making an issue here.

What I am doing:

Client

let observable: Observable = MeteorObservable.call('some.meteor.method');
...
observable.subscribe(()=>{
    console.log('subscription 1');
});
...
observable.subscribe(()=>{
    console.log('subscription 2');
});

SERVER

Meteor.methods({
    'some.meteor.method': function() {
        console.log('method called');
    }
});

What I am expecting in the server console:

method called

What I am actually getting in the server console:

method called
method called

The above is pseudo code to illustrate my point

For anyone else interested... for now I have implemented the following which meets my needs:

import { MeteorObservable } from 'meteor-rxjs';
import { Observable, Subject } from 'rxjs';

export class MeteorObservableOnce extends MeteorObservable {

    public static call<T>(name: string, ...args: any[]): Observable<T> {
        let subject: Subject<T> = new Subject();
        super.call.apply(this, arguments).subscribe(subject);
        return subject.asObservable();
    }

}

You could just as easily give the method another name and still keep access to the original call method

It seems my understanding of Observables was limited and the reason it has been done this way (as a 'cold Observable') is because there is no guarantee that subscribers won't miss the first data received from the server if the call is made before the subscribers are attached. However unlikely it might be that data will be 'lost' considering the delay in receiving data over the wire it still cannot be guaranteed.

The way to go is probably to create a ConnectableObservable and work with that. For future reference here is a link to an excellent post about the difference between hot & cold Observables:

https://blog.thoughtram.io/angular/2016/06/16/cold-vs-hot-observables.html