3

What is the best way to determine if the subscriber has finished executing or better yet return something and catch it up-stream? For example:

    this._subscriptions.push(this._client
        .getCommandStream(this._command) // Returns an IObservable from a Subject stream
        .subscribe(msg => {
            // Do some processing maybe some promise stuff
            http.request(url).then(
                // some more stuff
            );
        });

What's the best know to determine that subscription has finished. I've implemented it as follows:

    this._subscriptions.push(this._client
        .getCommandStream(this._command)
        .subscribe(msg => {
            // Do some processing maybe some promise stuff
            http.request(url).then(re => {
                // some more stuff
                msg.done()
            }).catch(err => msg.done(err));
        });

i.e. added a done method to the object being passed in to determine if this is finished. The issue with that is I'll have to call done in every promise or catch block and find that a little too exhaustive. Is there a cleaner and more automated way of doing this?

I think the examples I've given are not good enough. This implementation is using RX to build an internal messaging bus. The get command stream is actually returning a read-only channel (as an Observable) to get commands and process them. Now the processing could be a http request followed by many other things or just an if statement.

this._client
.getCommandStream(this._command) // Returns an IObservable from a Subject stream
  .subscribe(msg => {
      // Do some processing maybe some promise stuff
      http.request(url).then({
          // some more stuff

          }).then({
            // Here I wanna do some file io
            if(x) {
                file.read('path', (content) => {
                    msg.reply(content);
                    msg.done();
                });
            } else {
            // Or maybe not do a file io or maybe even do some image processing
                msg.reply("pong");
                msg.done()
            }
            });
      });

I feel like this is a fine usage of the Observable pattern as this is exactly a sequence of commands coming in and this logic would like to act on them. The question is notice msg.done() being called all over the place. I want to know what is the best way to limit that call and know when the entire thing is done. Another option is to wrap it all in a Promise but then again what's the difference between resolve or msg.done()?

halfer
  • 19,824
  • 17
  • 99
  • 186
Arijoon
  • 2,184
  • 3
  • 24
  • 32
  • 1
    You have just described a callback scenario, which is very common in most javascript frameworks. – atheaos May 01 '17 at 16:55
  • @atheaos so the way I've done it is fine and cannot be improved by an automated system? Also is it possible to catch all exception thrown by the subscriber or new callbacks started from within the subscriber? – Arijoon May 01 '17 at 17:44
  • 1
    This seems like a good question to me, but please do not add voting commentary or advice to your posts. Readers overwhelmingly do not sign into Stack Overflow, never mind also vote, so this material is not of interest to them. Moreover, downvoters will have gone by the time you comment, and they will not return to read your complaint `:-)`. It is nice when people support their vote with a comment, but they are not obligated to. – halfer May 02 '17 at 18:03

2 Answers2

1

Actually, making another asynchronous request inside subscribe() isn't recommended because it just makes things more complicated and using Rx in this way doesn't help you make your code more understandable.

Since you need to make a request to a remote service that returns a PRomise you can merge it into the chain:

this._subscriptions.push(this._client
    .getCommandStream(this._command)
    .concatMap(msg  => http.request(url))
    .subscribe(...)

Also the 3rd parameter to subscribe is a callback that is called when the source Observable completes.

You can also add your own teardown logic when the chain is being disposed. This is called after the complete callback in subscribe(...) is called:

const subscription = this._subscriptions.push(this._client
    ...
    .subscribe(...)

subscription.add(() => doWhatever())

Btw, this is equivalent to using the finally() operator.

martin
  • 93,354
  • 25
  • 191
  • 226
  • Thanks for the answer. I am aware of Map function but doubt it's easier to understand in this case as that implies the object being passed to the subscriber needs changing. This is not true, same object is required and processing is done on parts of it. Please see my updated answer for a better example – Arijoon May 02 '17 at 12:07
  • Can you link the description of `concat` operator, the only one I can find concats multiple observable streams into one. but here there is only one stream, and a processor which wishes to process a command on publishes on the stream. – Arijoon May 02 '17 at 16:36
  • http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#static-method-concat – martin May 02 '17 at 17:02
  • I might be just too stupid to see but I can't figure out how concat will help. It is merge two observable streams. There is only 1 stream in my question. – Arijoon May 02 '17 at 18:44
0

As per RxJs subscribe method documentation, the last Argument is completed function

var source = Rx.Observable.range(0, 3)

var subscription = source.subscribe(
  function (x) {
    console.log('Next: %s', x);
  },
  function (err) {
    console.log('Error: %s', err);
  },
  function () {
    console.log('Completed');
  });

please refer this documentation

https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/subscribe.md

Vikas Sardana
  • 1,593
  • 2
  • 18
  • 37
  • yes that is the first thing I found, but it is opposite what I'm asking. That is a callback to the stream being completed. i.e. you shut down the `IObservable`. I was asking how can the Observable object know if the subscriber callback has finished executing. Or if everything that is listening to it's msges, have finished processing that message or threw up. – Arijoon May 01 '17 at 17:43