3

I am not sure how correct I am on this so if any experts are able to correct me on this it would also be appreciated. My current understanding is that observables are lazy and do not produce values until subscribed to. If an error occurs the observable sends no more values. In a lot of cases this is not what is wanted.

In the code sample below I am getting the weather for perth and london and if an error occurs returning an object indicating the error has occured. This pretty much means that the error block on the subscriber will not get called but the success will and I will have to look at whether it failed and change logic. Is this the best way to do this????

Also does the zip operator wait for all obs to produce a value regardless of ordering and return when a single value from all has been produced?

Code as below:

window.application = application || {};

window.application.stocks = (function(){


    function getWeather(city, country){

        return $.ajaxAsObservable({
            url: 'http://api.openweathermap.org/data/2.5/weather?q=' + city + ',' + country,
            dataType: 'jsonp'
        }).map(function(v){
            return {
                city : city,
                country : country,
                temperature : v.data.main.temp
            };
        });
    }

    var requests = Rx.Observable
                  .interval(500)
                  .timestamp()
                  .map(function(v){
                     var perth = getWeather('perth','au');
                     var london = getWeather('london','uk');

                     return Rx.Observable.zip(perth,london, function(a,b){
                         return {
                             a : a,
                             b : b,
                             timestamp : v.timestamp,
                             failure : false,
                         };
                     }).retry(3)
                       .catch(Rx.Observable.return({ failure: true }));

                   })
                  .concatAll();

    var selector = $('#weather');

    var subscriber = requests.forEach(
        function(data){

            if(data.failure){
                $('<li>Failure in receiving the temperature</li>').appendTo(selector);
                return;
            }

            $('<li> at: ' + data.timestamp + ' for: '  + data.a.city + ' - ' + data.a.temperature + '</li>').appendTo(selector);
            $('<li> at: ' + data.timestamp + ' for: '  + data.b.city + ' - '  + data.b.temperature + '</li>').appendTo(selector);
        },
        function(error){
            selector.text('');
            $('<li>Error: ' + error + '</li>').appendTo('#weather');
        },
        function(){

        }
    );

});

Any suggestions and tips is greatly appreciated.

Thanks in advance.

Blair.

Blair Davidson
  • 901
  • 12
  • 35

2 Answers2

3

You probably should replace .forEach() with .subscribe() since one is an alias of the other, and .subscribe() is more common and more explicit in this case.

subscribe() can accept three functions as arguments onNext (first function), onError (second function, optional), onComplete (third function, optional). Hence, you probably will achieve what you want by just providing a second function in the subscribe(), to handle errors. Then you don't need the .catch() operator to insert a flag-like event.

Also, for your specific use case, where perth and london Observables are conceptually independent (they have no dependencies with one another), you want to use .combineLatest() instead of .zip(). See this answer for details on the difference between the two.

Community
  • 1
  • 1
André Staltz
  • 13,304
  • 9
  • 48
  • 58
0

Interesting as this post says that you do need to flag errors so that the steam does not complete.

Idiomatic way to recover from stream onError

From my current understanding and testing of RX if an error is thrown during process the onError handler of the subscription will get called but it will complete the stream.

Meaning that the subscriber will receive no further messages.

Community
  • 1
  • 1
Jeffxor
  • 231
  • 1
  • 2
  • 6
  • 2
    This doesn't necessarily provide an answer to the question. While good insight, it should be posted as a comment. When you gain enough reputation, you will be able to leave comments on questions, answers and other posts, but until then, try not to answer questions with another question. – Tim Lewis Jan 07 '15 at 21:47